Исключение индекса вне диапазона в пуле потоков в C# -Task.Run () - PullRequest
0 голосов
/ 13 января 2020

Когда я удаляю пул потоков или раскомментирую 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 Ответ

0 голосов
/ 13 января 2020

При вызове tasksInFlight.Add(updateDt(index, "col " + index)); значение индекса не читается; вы просто сохраняете задачу, которая будет выполнена позже - когда вы вызываете Task.WhenAll. Это когда задачи выполняются, когда оценивается значение index. Что происходит после окончания l oop и значения 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 блокировка исключает все преимущества параллелизма в этом случае.

...