如何正确使用并行计算对集合进行写操作?

复制代码
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;

namespace ParallelTest1
{
public class CalcTask
{
public event EventHandler<TaskItemEventArgs> OnTaskFinish;

public void ExecuteTasks()
{
int icount = 100;
List
<Task> items = new List<Task>(icount);
PInitializeTask(items, icount);
Console.WriteLine(items.Count);

List
<Task> items2 = new List<Task>();
SInitializeTask(items2, icount);

Console.WriteLine(items2.Count);

Console.ReadKey();
}

private void PInitializeTask(List<Task> items,int iCount)
{
Stopwatch stopwatch
= new Stopwatch();
stopwatch.Start();

Parallel.For(
0, iCount, new ParallelOptions()
{

}, i
=>
{
lock (items) //如果不加锁,观察最终集合的个数?
{
items.Add(
new Task()
{
Source
= i,
Dest
= i + i,
});

//if (items.Count == iCount)
OnTaskFinish(this, new TaskItemEventArgs()
{
ThreadId
=Thread.CurrentThread.ManagedThreadId,
Data
=items,
});
}
});

stopwatch.Stop();
Console.WriteLine(
"Parallel loop time in milliseconds: {0}", stopwatch.ElapsedMilliseconds);

}

private void SInitializeTask(List<Task> items, int iCount)
{
Stopwatch stopwatch
= new Stopwatch();
stopwatch.Start();
for(int i=0;i<iCount;i++)
{
items.Add(
new Task()
{
Source
= i,
Dest
= i + i,
});

OnTaskFinish(
this, new TaskItemEventArgs()
{
ThreadId
= Thread.CurrentThread.ManagedThreadId,
Data
= items,
});
}
stopwatch.Stop();
Console.WriteLine(
"Sequential loop time in milliseconds: {0}", stopwatch.ElapsedMilliseconds);
}
}

public class Task
{
public int Source { get; set; }
public int Dest { get; set; }

public override string ToString()
{
return string.Format("{0}-{1}", this.Source, this.Dest);
}
}

public class TaskItemEventArgs:EventArgs
{
public int ThreadId{get;set;}
public object Data{get;set;}
}
}
复制代码
 
复制代码
static void Main(string[] args)
{
Console.WriteLine(
"Processor Count:" + Environment.ProcessorCount);
CalcTask task1
= new CalcTask();
task1.OnTaskFinish
+= new EventHandler<TaskItemEventArgs>((sender, e) =>
{
Console.WriteLine(
string.Format("Finish:{0}-{1}", e.ThreadId, (e.Data as List<Task>).Count));
});
task1.ExecuteTasks();


}
复制代码
在上述代码中,我测试的结果规律如下:
如果并行中,不加lock,如果是向集合填充100万个对象 ,那么并行代码 执行完毕后,那个集合的数目永远都是小于100万,我的结果显示是80多万。。。。估计中间发生冲突导致部分的项添加不成功,但是.net并没有报错,这样很容易让我们中招。所以用一般集合时需要小心,这里也证实了一般的集合List<T>并不是线程安全的。。。
后来我换成System.Collections.Concurrent.ConcurrentDictionary<int, Task>试了下,发现不用加lock,结果也是正确的,所以大家在并行运算中记得多使用这个哈希结构。。。但是线程安全的。
posted @   linus_wang  阅读(333)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示