Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.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# 对一次性对象使用wait Async WhenAll_C#_Design Patterns_Async Await_Idisposable - Fatal编程技术网

C# 对一次性对象使用wait Async WhenAll

C# 对一次性对象使用wait Async WhenAll,c#,design-patterns,async-await,idisposable,C#,Design Patterns,Async Await,Idisposable,在使用一次性对象时,我遇到了一个问题,即试图并行处理多个任务(或者以运行时感觉合适的方式)。在下面的代码段中,每个处理器对象在完成所需工作之前都会立即被释放 async public Task ProcessData(IEnumerable<int> data) { var tasks = new List<Task>(); foreach (var d in data) { using (var processor = new

在使用一次性对象时,我遇到了一个问题,即试图并行处理多个任务(或者以运行时感觉合适的方式)。在下面的代码段中,每个处理器对象在完成所需工作之前都会立即被释放

async public Task ProcessData(IEnumerable<int> data)
{
    var tasks = new List<Task>();

    foreach (var d in data)
    {
        using (var processor = new Processor(d))
        {
            processor.Completed += (sender, e) => { // Do something else };
            tasks.Add(processor.ProcessAsync());
        }
    }

    await Task.WhenAll(tasks);
}
异步公共任务ProcessData(IEnumerable数据) { var tasks=新列表(); foreach(数据中的var d) { 使用(var处理器=新处理器(d)) { processor.Completed+=(发送方,e)=>{///做点别的事情}; tasks.Add(processor.ProcessAsync()); } } 等待任务。何时(任务); } 按照以下方式重新编写代码会导致每个处理器执行其处理,然后被释放,但这并不是运行多个互不依赖的任务的最有效方式

async public Task ProcessData(IEnumerable<int> data)
{
    foreach (var d in data)
    {
        using (var processor = new Processor(d))
        {
            processor.Completed += (sender, e) => { // Do something else };
            await processor.ProcessAsync();
        }
    }
}
异步公共任务ProcessData(IEnumerable数据) { foreach(数据中的var d) { 使用(var处理器=新处理器(d)) { processor.Completed+=(发送方,e)=>{///做点别的事情}; 等待处理器。ProcessAsync(); } } }
有人能解释为什么第一个示例是“提前”处理,并给出一个针对这种情况的最佳代码模式的示例。

wait
看作是暂停当前方法,即使它不会阻止线程

在第一个示例中,当执行
foreach
循环时,每次创建
处理器时,启动一个操作(将操作的
任务保存在列表中),然后处置
处理器。在
foreach
循环完成后,您(异步)等待所有操作完成

在第二个示例中,当执行
foreach
循环时,每次创建
处理器时,启动一个操作,(异步)等待它完成,然后处置
处理器

要解决此问题,您应该编写一个助手方法,如下所示:

private static async Task ProcessData(int data)
{
  using (var processor = new Processor(d))
  {
    processor.Completed += (sender, e) => { /* Do something else */ };
    await processor.ProcessAsync();
  }
}
您的helper方法定义了一个更高级别的操作,该操作将负责在适当的时间处理自己的
处理器
资源。然后您可以同时开始所有工作,如下所示:

public async Task ProcessData(IEnumerable<int> data)
{
  ...
  await Task.WhenAll(data.Select(d => ProcessData(d)));
  ...
}
公共异步任务ProcessData(IEnumerable数据)
{
...
wait Task.WhenAll(data.Select(d=>ProcessData(d));
...
}

尽管Stephen Cleary的回答很优雅,而且在本例中可能是更好的选择,但我认为值得注意的是,作为反应式扩展(Rx)的一部分,您可以在类似场景中获得一些有用的东西。它提供了一组与
IDisposable
相关的帮助程序,使您能够执行以下操作:

public async Task ProcessData(IEnumerable<int> data)
{
    var tasks = new List<Task>();

    using (var disp = new CompositeDisposable())
    {
        foreach (var d in data)
        {
            var processor = new Processor(d);
            disp.Add(processor);
            processor.Completed += (sender, e) =>
                {
                    // Do something else
                };
            tasks.Add(processor.ProcessAsync());
        }
        await Task.WhenAll(tasks);
    }
}
公共异步任务ProcessData(IEnumerable数据)
{
var tasks=新列表();
使用(var disp=new CompositeDisposable())
{
foreach(数据中的var d)
{
var处理器=新处理器(d);
显示添加(处理器);
处理者。已完成+=(发送者,e)=>
{
//做点别的
};
tasks.Add(processor.ProcessAsync());
}
等待任务。何时(任务);
}
}
要得到它,您需要对
Rx Main
的NuGet引用


我不认为我会在这种情况下使用它,但我想我会尽量避免到达一个我需要这样的代码的地方。既有一个
任务
来表示您的
处理器所做的工作
,又有一个事件来表示…某件事?它已完成。。?嗯,
Task
可以帮你做到这一点,那么为什么两者都有呢?事件相对混乱-我总是发现Rx
IObservable
或直接使用
Task
是比依赖事件更好的解决方案。

为什么需要在该范围内处理处理器对象?无论如何,处理器对象会被释放,因为你要为循环中的每一圈离开使用范围。我想我希望编译器会在幕后发挥一些魔力,并自动将处理设置为一系列连续。编译器确实将处理设置为一系列连续,但仅当
using
块中存在
wait
时。第一个示例的基本问题是编译器完全无法知道每个
处理器的处理需要与任何特定任务的生命周期相关联。helper方法是这个优雅解决方案的关键。它围绕着简单的ProcessAsync包装了一个更复杂的异步工作流。是的,当我和Matthew坐下来时,我们讨论了从事件模型中移除。这只是一个尚未完全异步的代码示例。