我必须编写一些需要我返回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()方法运行完成?
澄清:由于'导致任何问题',我的意思是在执行上述操作时是否有任何令人担忧的问题?死锁,未被观察到的异常等......?我问,因为我知道异步编程中有许多细微之处并不总是显而易见的,比我更了解的人可能会指出一个可能的问题,或者可能知道更好的方法来实现什么我的目标是......
答案 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
,你显然不能同时阻止他们中的任何一个。)