Vla*_*rov 7 c# lambda multithreading .net-4.0 task-parallel-library
我的问题是,在下面的代码中,我可以确定实例方法将访问我认为它们将要的变量,还是可以在我还在工作时由另一个线程更改?闭包与此有什么关系,即我是否会在IEnumerable<T>这样的枚举的本地副本上工作是否安全?
为了解释我的问题,如果我从不写共享变量,我是否需要任何锁定?
public class CustomerClass
{
private Config cfg = (Config)ConfigurationManager.GetSection("Customer");
public void Run()
{
var serviceGroups = this.cfg.ServiceDeskGroups.Select(n => n.Group).ToList();
var groupedData = DataReader.GetSourceData().AsEnumerable().GroupBy(n => n.Field<int>("ID"));
Parallel.ForEach<IGrouping<int, DataRow>, CustomerDataContext>(
groupedData,
() => new CustomerDataContext(),
(g, _, ctx) =>
{
var inter = this.FindOrCreateInteraction(ctx, g.Key);
inter.ID = g.Key;
inter.Title = g.First().Field<string>("Title");
this.CalculateSomeProperty(ref inter, serviceGroups);
return ctx;
},
ctx => ctx.SubmitAllChanges());
}
private Interaction FindOrCreateInteraction(CustomerDataContext ctx, int ID)
{
var inter = ctx.Interactions.Where(n => n.Id = ID).SingleOrDefault();
if (inter == null)
{
inter = new Interaction();
ctx.InsertOnSubmit(inter);
}
return inter;
}
private void CalculateSomeProperty(ref Interaction inter, IEnumerable<string> serviceDeskGroups)
{
// Reads from the List<T> class instance variable. Changes the state of the ref'd object.
if (serviceGroups.Contains(inter.Group))
{
inter.Ours = true;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我似乎找到了答案,在这个过程中,也找到了问题。
真正的问题是,实际上是对象的本地“变量”是否可以被信任以进行并发访问。答案是否定的,如果它们碰巧有未以线程安全方式处理的内部状态,那么所有的赌注都会失败。闭包没有帮助,它只是捕获对所述对象的引用。
在我的具体情况下 - 并发读取IEnumerable<T>但不写入,它实际上是线程安全的,因为每次调用foreach、Contains()、Where()等都会得到一个全新的 new IEnumerator,它仅在请求它的线程中可见。然而,任何其他物体也必须一一检查。
所以,万岁,对我来说没有锁或同步集合:)
感谢@ebb和@Dave,虽然你们没有直接回答问题,但你们为我指明了正确的方向。
如果您对结果感兴趣,这是在我的家用电脑(四核)上运行的,用于Thread.SpinWait模拟一行的处理时间。真实的应用程序在本地网络上具有 SQL Server 的双核超线程计算机上的性能提高了近 2 倍(01:03 与 00:34)。
单线程,使用foreach. 我不知道为什么,但跨核心上下文切换的数量相当多。
在需要时使用Parallel.ForEach带有线程局部变量的无锁。
| 归档时间: |
|
| 查看次数: |
638 次 |
| 最近记录: |