Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 进程未使用ParallelForEachAsync并行运行_C#_Parallel Processing_Parallel.foreach - Fatal编程技术网

C# 进程未使用ParallelForEachAsync并行运行

C# 进程未使用ParallelForEachAsync并行运行,c#,parallel-processing,parallel.foreach,C#,Parallel Processing,Parallel.foreach,我正在测试通过进程运行python 我的机器有一个2.8GHz的CPU,有4个内核和8个逻辑处理器 我的主控制台应用程序如下 static void Main(string[] args) => MainAsync(args).GetAwaiter().GetResult(); static async Task MainAsync(string[] args) { var startTime = DateTime.UtcN

我正在测试通过进程运行python

我的机器有一个2.8GHz的CPU,有4个内核和8个逻辑处理器

我的主控制台应用程序如下

    static void Main(string[] args) => MainAsync(args).GetAwaiter().GetResult();

    static async Task MainAsync(string[] args)
    {            
        var startTime = DateTime.UtcNow;
        Console.WriteLine($"Execution started at {DateTime.UtcNow:T}");

        await ExecuteInParallelAsync(args).ConfigureAwait(false);
        Console.WriteLine($"Executions completed at {DateTime.UtcNow:T}");
        var endTime = DateTime.UtcNow;

        var duration = (endTime - startTime);
        Console.WriteLine($"Execution took {duration.TotalMilliseconds} milliseconds {duration.TotalSeconds} seconds");

        Console.WriteLine("Press Any Key to close");
        Console.ReadKey();            
    }
其中ExecuteInParallelAsync是执行此工作的方法

    private static async Task ExecuteInParallelAsync(string[] args)
    {
        var executionNumbers = new List<int>();
        var executions = 5;

        for (var executionNumber = 1; executionNumber <= executions; executionNumber++)
        {
            executionNumbers.Add(executionNumber);
        }

        await executionNumbers.ParallelForEachAsync(async executionNumber =>
        {
             Console.WriteLine($"Execution {executionNumber} of {executions} {DateTime.UtcNow:T}");
            ExecuteSampleModel();
            Console.WriteLine($"Execution {executionNumber} complete {DateTime.UtcNow:T}");
        }).ConfigureAwait(false);
    }
如你所见,我要求这个模型执行5次

当我使用调试器时,似乎即使我使用的是ParalellForEach(由AsyncEnumerator包引入),这也不是并行运行的

我认为每个迭代都是在自己的线程上运行的

每个Python模型执行需要5秒钟

并行运行时,我希望整个过程在15秒左右完成,但实际上需要34秒

在调用GetResponse之前和之后添加的Console.WriteLines显示第一个调用正在启动、正在完全执行,然后第二个调用正在启动,等等

这和我呼叫过程有关吗?开始

有人能看出这有什么问题吗


Paul

为了让答案有用,这里解释一下异步代码发生了什么。从解释的角度来看,省略了许多不太重要的细节,
ParallelForEachAsync
循环中的代码如下所示:

// some preparations
...
var itemIndex = 0L;
while (await enumerator.MoveNextAsync(cancellationToken).ConfigureAwait(false))
{
    ...
    Task itemActionTask = null;
    try
    {
        itemActionTask = asyncItemAction(enumerator.Current, itemIndex);
    }
    catch (Exception ex)
    {
       // some exception handling
    }
    ...
    itemIndex++;
}
其中,
asyncItemAction
具有类型
Func
,它是一个围绕自定义异步操作的包装器,类型为
Func
,作为参数传递给
ParallelForEachAsync
调用(包装器添加了索引功能)。循环代码只是调用此操作,以获得一个任务,该任务表示异步操作承诺等待其完成。对于给定的代码示例,自定义操作

async executionNumber =>
{
     Console.WriteLine($"Execution {executionNumber} of {executions}{DateTime.UtcNow:T}");
     ExecuteSampleModel();
     Console.WriteLine($"Execution {executionNumber} complete {DateTime.UtcNow:T}");
}
不包含异步代码,但前缀
async
允许编译器使用返回一些
Task
的方法生成状态机,该方法使代码与循环内的自定义操作调用兼容(从语法角度看)。 重要的是,循环中的代码希望此操作是异步的,这意味着该操作隐式地分为同步部分,同步部分将与
asyncItemAction(enumerator.Current,itemIndex)
调用和至少一个(一个或多个取决于
内部等待的
数量)一起执行可以在迭代其他循环项期间执行的异步部分。下面的伪代码给出了一个想法:

 {
     ... synchronous part
     await SomeAsyncOperation();
     ... asynchronous part
 } 
在这种特殊情况下,自定义操作中根本没有异步部分,这意味着调用

 itemActionTask = asyncItemAction(enumerator.Current, itemIndex);
将同步执行,循环中的下一个迭代将在
asyncItemAction
完成整个自定义操作执行之前不会启动


这就是为什么关闭代码中的异步并使用简单的并行性会有所帮助。

我不确定
ParallelForEachAsync
是如何工作的,因为它不是标准API的一部分,但我认为它需要一些在代码中没有的东西,所以我怀疑它是否能正常工作。由于
GetResponse
中没有异步代码,所以不清楚为什么决定使用异步而不是简单的
Parallel.ForEach
。删除了我的误导性答案。经过一些额外的测试,结果表明,
ParallelForEachAsync
的规则与
Parallel.ForEach
的规则不同(我认为它们是等价的)。Dmytro Mukalov关于
ParallelForEachAsync
的本质是正确的。在您的情况下,使用
Parallel.ForEach
会更好更容易,但是如果您想坚持使用
ParallelForEachAsync
请参阅。这是将同步代码转换为异步代码的一般方法。好的,谢谢。我不明白为什么我的问题被降级了,我在里面放了很多信息
 itemActionTask = asyncItemAction(enumerator.Current, itemIndex);