c# - 多线程、lambdas 和局部变量

标签 c# multithreading .net-4.0 lambda 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;
        }
    }
}

最佳答案

我似乎找到了答案,在这个过程中,也找到了问题。

真正的问题是本地“变量”,实际上是对象,是否可以信任并发访问。答案是否定的,如果它们恰好具有未以线程安全方式处理的内部状态,则所有赌注都将取消。闭包没有帮助,它只是捕获对所述对象的引用。

在我的具体情况下 - 从 IEnumerable<T> 并发读取并且没有写入它,它实际上是线程安全的,因为每次调用 foreach , Contains() , Where()等获得全新的IEnumerator ,这仅在请求它的线程中可见。然而,任何其他对象也必须一一检查。

所以,万岁,对我来说没有锁或同步集合:)

感谢@ebb 和@Dave,虽然你们没有直接回答问题,但你们为我指明了正确的方向。


如果您对结果感兴趣,这是在我的家用 PC(四核)上运行的 Thread.SpinWait模拟一行的处理时间。在本地网络上装有 SQL Server 的双核超线程机器上,真实应用程序的性能提高了近 2 倍(01:03 与 00:34)。

Singlethreaded 单线程,使用foreach .我不知道为什么,但是有相当多的跨核上下文切换。

Multithreaded 使用 Parallel.ForEach ,在需要时使用线程局部变量进行无锁。

关于c# - 多线程、lambdas 和局部变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8390967/

相关文章:

c# - 为什么以下条件运算符在包含 Nullable 类型的 StringBuilder 中运行异常?在 C# 中?

c# 如何从字符串导入powershell模块

c - 使用线程改进一个简单的函数

.net - OrderedDictionary 在 .NET 4 中发生了重大变化?

c# - 将属性名称作为字符串传递到方法中 .NET

c# - 从 native 可视化 C++ 代码调用 C# .dll

c++ - 在 C/C++ 中实现跨平台、多线程服务器的最佳方法是什么?

java - 如何在单独的 java 类中引用线程?

c# - EntityFramework 中的 ObjectDisposedException

MSBUILDEMITSOLUTION 不适用于 .NET 4?