C#中的线程池中的索引超出范围异常-Task.Run()

问题描述 投票:0回答:1

当我从代码中删除线程池或取消注释Console.WriteLine()时,代码可以正常工作,但是为了提高性能,我想在单独的Task上处理每个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)
        {
        }
    }
multithreading async-await task threadpool multitasking
1个回答
0
投票

当您调用tasksInFlight.Add(updateDt(index, "col " + index));时,不会读取索引值;您仅存储将在以后执行的任务-当您调用Task.WhenAll时。在评估index的值时执行任务。在循环结束并且index的值现在等于dt.Columns.Count时发生,该值超出数组的范围。

了解C#闭包here

要修复它,您可以这样做:

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

EDIT:经过进一步调查,结果证明DataTable不是线程安全的。

除了上述修复之外,还应该以锁定方式访问DataTable:

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

但是,除非在这种情况下,除非获取实际数据以占用CPU大量资源,否则锁将消除并发的所有好处。

© www.soinside.com 2019 - 2024. All rights reserved.