我经常编写具有便捷方法的代码,基本上包装其他方法。这是一个简单的例子:
public class WithoutAsync
{
public static ReadOnlyCollection<Response> GetResponses(IEnumerable<Request> fromRequests)
{
var ret = new List<Response>();
foreach (Request r in fromRequests)
{
ret.Add(new Response());
}
return ret.AsReadOnly();
}
//convenience method
public static Response GetResponse(Request fromRequest)
{
return GetResponses(new Request[] {fromRequest})[0];
}
}
现在我想await
长时间运行但我无法弄清楚如何改进此方法以用于TPL:
public class WithAsync
{
public static async Task<ReadOnlyCollection<Response>> GetResponses(IEnumerable<Request> fromRequests)
{
var awaitableResponses = new List<Task<Response>>();
foreach (Request r in fromRequests)
{
awaitableResponses.Add(Task.Run<Response>(async () =>
{
await Task.Delay(10000); //simulate some long running async op.
return new Response();
}));
}
return new List<Response>(await Task.WhenAll(awaitableResponses)).AsReadOnly();
}
//convenience method
public static Task<Response> GetResponse(Request fromRequest)
{
return GetResponse(new Request[] { fromRequest });
}
}
上面的便捷方法显然不会起作用,因为当它确实需要返回Task<ReadOnlyCollection<Response>>
时,它会尝试返回Task<Response>
。
这有效:
//convenience method
public static Task<Response> GetResponse(Request fromRequest)
{
return new Task<Response>(new Func<Response>(() => GetResponse(new Request[] { fromRequest }).Result[0]));
}
但它看起来真的很尴尬,更重要的是,它会在.Result[0]
上阻塞,这可能是在UI线程上。
有没有什么好办法可以完成我想要做的事情?
答案 0 :(得分:5)
你试图避免使用“方便方法”async
,但没有理由这样做。
你想要的是调用另一种方法,等到有响应,然后得到第一个也是唯一一个。您可以通过async
并使用await
:
async Task<Response> GetResponseAsync(Request fromRequest)
{
var responses = await GetResponsesAsync(new[] { fromRequest });
return responses.Single();
}
虽然在这种特定情况下更好的解决方案是切换周围的事情并让单个GetResponse
实际执行单个请求的工作,并让多个GetRsponses
调用它:
async Task<ReadOnlyCollection<Response>> GetResponsesAsync(IEnumerable<Request> fromRequests)
{
return (await Task.WhenAll(fromRequests.Select(GetResponse))).ToList().AsReadOnly();
}
async Task<Response> GetResponseAsync(Request fromRequest)
{
await Task.Delay(10000); //simulate some long running async op.
return new Response();
}
注意:
Task.Run
而不是简单的async
来电。async
方法命名为“Async”后缀(即GetResponseAsync
)。答案 1 :(得分:0)
我仍然坚持I3arnon的答案,因为它写得很好,信息量很大,但我想提交自己的答案,因为我意识到我差不多那里。这是我努力寻找的async
便利方法:
//convenience method
public static async Task<Response> GetResponse(Request fromRequest)
{
return (await GetResponses(new Request[] { fromRequest }))[0];
}