如何从执行任务列表中返回任务

时间:2015-12-08 05:06:33

标签: c# asynchronous async-await

我必须编写一些需要我返回Task对象的中间件代码。我的中间件代码还使用一个框架,该框架异步地将数据发送到连接的客户端,返回一个Task。

到目前为止非常直接。

但是我的用例是我有很多连接的客户端。所以我的问题基本上是,调用每个客户端的异步Send方法最明智的方法是什么,更重要的是,我应该返回的Task是什么。我正在使用c#5。

class Client // some framework
{
    public Task Send(Object message)
    {
        // does its thing somehow, returns a Task
    }
}


interface Handler<TMessage> // some framework
{
    Task Handle(TMessage msg);
}

class Middleware : Handler<Object> // my middleware implementation code
{
    List<Client> clients;

    public Task Handle(Object msg)
    {
        //i do some stuff here before calling each client's Send method

        return Task.Run(() => clients.ForEach(client => client.Send(msg))); <-- my current solution
    }
}

简而言之,我收到一条消息(处理程序),我执行一些自定义逻辑(过滤客户端等),然后调用每个客户端async Send方法。根据自定义逻辑的性质而不同,我可能希望将该代码包装在Task内。对此的任何建议也将不胜感激。

我的困惑是,我应该返回我创建的外部Task吗?或者是否有一些其他首选的方法来执行我不知道的每个异步方法。

修改

Send方法是异步的,即使它没有命名为SendAsync。请记住,它是一个框架调用,因此我无法按照建议将其重命名为SendAsync。但是,请放心,它是一个异步调用,并返回Task

鉴于呼叫的真正异步性质,我使用的是:

return Task.Run(() => clients.ForEach(client => client.Send(msg)));

会导致任何问题,因为我不想等待每个客户端的异步Send()方法运行完成?

澄清:由于'导致任何问题',我的意思是在执行上述操作时是否有任何令人担忧的问题?死锁,未被观察到的异常等......?我问,因为我知道异步编程中有许多细微之处并不总是显而易见的,比我更了解的人可能会指出一个可能的问题,或者可能知道更好的方法来实现什么我的目标是......

1 个答案:

答案 0 :(得分:4)

由于Send()方法是异步的并返回Task,因此您应该执行以下操作:

public Task Handle(Object msg)
{
    return Task.WhenAll(clients.Select(client => client.Send(msg)));
}

WhenAll()方法将枚举Task个对象的序列(从原始client值投影),并返回表示所有对象完成的Task对象

。客户端Task返回的对象。


您应该考虑更改(或鼓励该代码的所有者更改)Send()方法的名称,以便其中包含单词Async(例如SendAsync())。显然,编译器并不关心你所谓的方法,但是这种约定对于理解基于异步的代码非常有用。


附录:

从您的修订到问题:

  

鉴于我不想等待每个客户端的异步Send()方法运行完成?

如果您不想等待每个客户的完成,那么只需启动每项操作即可。我没有理由使用Task来开始操作:

public void Handle(Object msg)
{
    //i do some stuff here before calling each client's Send method

    clients.ForEach(client => client.Send(msg));
}

根据定义,异步方法在完成之前返回。按照惯例,它会很快完成。因此,不需要将ForEach()的执行包装在Task中,也不需要Handle()本身完全异步(至少,不是对于此特定语句)方法)。

  

我的意思是,在执行上述操作时是否有任何令人担忧的问题?死锁,未被观察到的异常等......?

当然,至少根据您目前提供的代码,您将无法观察到的异常情况。

至于死锁,我们无法知道你的代码是否会受到影响;没有什么可以启动异步操作,这本身就会产生死锁情况,也不会引发和忘记&#34;正如你在这里添加任何特定的死锁风险(如果有的话,可能降低风险,因为如果你根本没有为每个操作捕获Task,你显然不能同时阻止他们中的任何一个。)