【问题标题】:Return value and keyword inside a Parallel ForEach or For loopParallel ForEach 或 For 循环内的返回值和关键字
【发布时间】:2011-03-29 14:01:35
【问题描述】:

从并行 ForEach 或 For 循环返回值的正确方法是什么?

例如以下代码是否正确/线程安全?

{
    Process[] processes = Process.GetProcesses();
    String ProcessName = String.Empty;
    Parallel.ForEach(processes, curItem => {
        if (curItem.Handle == this._handle) {
            ProcessName = curItem.ProcessName;
            return;
        }
    });
    return ProcessName;
}

还是这个?

{
    Process[] processes = Process.GetProcesses();
    List<String> ProcessNames = new List<String>();
    Parallel.ForEach(processes, curItem => {
            ProcessNames.Add(processes.ProcessName);
        }
    });
    return ProcessNames;
}

最后,在 Parallel For 或 ForEach 循环中 return 关键字的行为是什么?

IE:它会立即终止所有线程吗?它会导致您可能没有预料到的任何伪影吗?

希望我的问题是有道理的。

PS:更具体一点。查看第一个示例是我对 String 线程安全的修改并包含我期望的值,因为 return 语句?在第二个示例中是我对 List Collection 线程安全的修改?会添加我期望的所有值吗?

【问题讨论】:

    标签: c# multithreading thread-safety parallel-processing task-parallel-library


    【解决方案1】:

    我会在这里使用 PLINQ:

    return Process
        .GetProcesses()
        .AsParallel()
        .SingleOrDefault(p => p.Handle == this._handle);
    

    我想知道您在这里处理的数据量是否值得并行...

    为了更直接地回答您的问题,为了处理从并行循环的提前退出,您应该查看将 ParallelLoopState 交给执行委托的重载。这可用于控制早期循环终止。

    编辑:

    您看到的错误是因为您的进程没有足够的权限来访问您检查的进程的句柄。处理此问题的蛮力方法如下:

    Process
    .GetProcesses()
    //.AsParallel()
    .Where(p=>{try{var h=p.Handle;}catch{return false;}return true;})
    .SingleOrDefault(p => p.Handle == this._handle)
    

    当然,假设this._handle指的是当前正在执行的进程的句柄:

    Process.GetCurrentProcess()
    

    肯定会更合适?

    【讨论】:

    • 我只是在玩弄这个概念。我想它可能不会。
    • 只有我一个人吗?上面的代码抛出以下错误:Win32Exception 未被用户代码处理。访问被拒绝 - 我猜这与比较句柄有关?
    • 在我的情况下,我有一个自己的自定义 Window 类。它实现了流程对象不提供的功能。我只是想避免另一个 API 调用并玩弄这个概念。看起来它在标准循环中也不起作用。哎呀!
    【解决方案2】:

    return 在并行 foreach 循环中与普通循环中的 continue 基本相同,因为 return 在为每个项目执行的委托中。这意味着,它不会终止任何线程,尤其是不会终止并行 foreach 循环的执行。

    【讨论】:

      【解决方案3】:

      以上所有答案+:

      如果你想发出循环应该停止的信号,你应该使用ParallelLoopState(你可以通过传递Action&lt;T, ParallelLoopState&gt;而不是Action&lt;T&gt;委托来访问这个对象。状态对象有像.Stop().Break()这样的方法将表明您想停止执行循环(以及其他一些有用的属性,请自行尝试)。

      【讨论】:

        【解决方案4】:

        都不对。您正在搜索一个值? Parallel.ForEach 在这里是错误的解决方案。您正在寻找的是reduction,而ForEach 执行的是mapping。可以使用 PLINQ 执行并行归约。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-10-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-01-14
          • 2016-02-02
          • 2011-11-25
          • 1970-01-01
          相关资源
          最近更新 更多