C# -Task.Run() 中线程池中的索引超出范围异常
Posted
技术标签:
【中文标题】C# -Task.Run() 中线程池中的索引超出范围异常【英文标题】:Index Out of Range Exception in Thread Pooling in C# -Task.Run() 【发布时间】:2020-04-30 01:48:31 【问题描述】:当我从代码中删除线程池或取消注释 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));
时,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));
编辑:经过进一步调查,事实证明 DataTable 不是线程安全的。
除了上面的修复,DataTable 应该被锁访问:
lock (dt)
dt.Rows[i][colNum] = data;
但是,除非检索实际数据以放入 DataTable CPU 密集型,否则在这种情况下,锁会消除并发性的所有好处。
【讨论】:
谢谢您,我尝试了您的解决方案,但仍然是同样的问题,有时代码运行顺利,但有时会出现索引超出范围异常。请帮忙。 在 dt.Rows[i][colNum] = data 处抛出异常; 超出范围 - i 还是 colNum? 当我调试并检查 'i' 和 'colNum' 值在有效范围内时。请帮忙 尝试记录异常值。以上是关于C# -Task.Run() 中线程池中的索引超出范围异常的主要内容,如果未能解决你的问题,请参考以下文章