Исключение индекса вне диапазона в пуле потоков в C # -Task.Run ()

Когда я удаляю пул потоков или удаляю комментарий Console.WriteLine () из кода, код работает нормально, но для повышения производительности я хочу обработать каждый столбец DataTable в отдельной задаче. Индекс выбрасывает исключение из диапазона.

DataTable dt = new DataTable();
private async void btnExcel_Click(object sender, RoutedEventArgs e)
    {
        dt = new DataTable("worksheet");
        dt.Columns.Add("Id");
        dt.Columns.Add("MobileNo");
        dt.Columns.Add("Name");
        dt.Columns.Add("Name1");
        dt.Columns.Add("Name2");
        dt.Columns.Add("Name3");
        dt.Columns.Add("Name4");

        for (int i = 0; i < 100; i++)
            dt.Rows.Add(i, "99999", "ABC" + i, "n1", "n2", "n3", "n4");

        //var tasksInFlight = new Task[dt.Columns.Count];
        var tasksInFlight = new List<Task>();

        for (int index = 0; index < dt.Columns.Count; index++)
        {
            tasksInFlight.Add(updateDt(index, "col " + index));

        }

        //await Task.Factory.ContinueWhenAll(tasksInFlight, cT => { string a = "abc"; });

        await Task.WhenAll(tasksInFlight);

    }


    public async Task updateDt(int colNum, string data)
    {
        try
        {
            Task t = Task.Run(() =>
            {
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                    // Console.WriteLine("Col Num : " + colNum + "  i = " + i);
                    dt.Rows[i][colNum] = data;
                }
            });

            await t;
        }
        catch (Exception ex)
        {
        }
    }

Всего 1 ответ


Когда вы вызываете tasksInFlight.Add(updateDt(index, "col " + index)); значение индекса не читается; вы просто сохраняете задачу, которая будет выполнена позже - когда вы вызываете Task.WhenAll . Это когда задачи выполняются, когда оценивается значение index . Что происходит после окончания цикла, и значение index теперь равно dt.Columns.Count , который находится вне диапазона массива.

Читайте о C # замыканиях здесь .

Чтобы это исправить, вы можете сделать так:

for (int index = 0; index < dt.Columns.Count; index++)
{
    int tmpIndex = index;
    tasksInFlight.Add(updateDt(tmpIndex, "col " + tmpIndex));
}

РЕДАКТИРОВАТЬ : После дальнейшего расследования выясняется, что DataTable не является потокобезопасным.

В дополнение к вышеприведенному исправлению DataTable должен быть доступен в замке:

 lock (dt) 
 { 
     dt.Rows[i][colNum] = data; 
 }

Однако, если не получить фактические данные для помещения в интенсивную ЦП DataTable, блокировка исключает все преимущества параллелизма в этом случае.