有关于在Parallel.ForEach()中调用外部方法的任何特殊规则或警告吗?

时间:2018-04-16 07:11:28

标签: c# .net multithreading

在Parallel.ForEach()中调用外部方法是否有任何特殊规则或注意事项?我想确保避免任何古怪的多线程问题。请考虑以下Parallel.ForEach()例程:

public void GetGroupUsers()
{
    Parallel.ForEach(
        groups.ToList(),
        new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount },
        group =>
    {
        //get associated user id's by group name
        userGuids = GetUserGuidsForGroup(1);

        //if no group-users then continue
        if (userGuids == null) return;

        //update group user map
        foreach (var userGuid in userGuids)
            groupUserMap.Add(new KeyValuePair<Guid, Guid>(group.Key, userGuid));
    });
}

private List<Guid> GetUserGuidsForGroup(int groupNumber)
{
    var userGuids = new List<Guid>();
    //do a repo lookup of user guids for the groupNumber parameter and add to list
    return userGuids;
}

1 个答案:

答案 0 :(得分:1)

  

在Parallel.ForEach()中调用外部方法是否有任何特殊规则或注意事项?

在编写简单的多线程应用程序时,规则/注意事项与您需要的相同。只是在这里线程是通过池配置的,而不是由用户创建的。当你调用.Net framework apis时,你仍然在调用外部/框架方法。在.Net框架api调用的情况下,您只需要确保每个线程都有自己的唯一对象来进行调用(因此线程安全)或共享对象在线程安全区域中进行方法调用。专注于Write调用(改变对象的状态)而不是Read调用。列举一些重要的:

  1. 避免竞争条件,不使用InterlockedLockSemaphore,{{1}等构造创建线程安全区域,不要编写/更新共享/全局/静态变量}}
  2. 尝试使用线程安全/并发集合,因为它们做得更好,因为您不需要担心显式同步
  3. 读取通常是线程安全的,但是写入不是并且可能导致Race条件(更常见),死锁(所有这些都很容易避免使用Concurrent集合)
  4. 使用像mutex / ThreadLocal这样的东西,要小心,因为这里要处理ThreadStatic,这意味着同一个线程可以/将用于多次迭代,因此它会保留您可能不期望的本地状态,因此可能需要显式重置此类变量的状态。这通常会导致问题。
  5. 区分IO调用和计算调用,因为number_of_threads != number_of_Elements API不适合IO绑定调用,Parallel是更好的选择