在同步foreach中调用异步

问题描述 投票:1回答:2

我有一个带有eventCallback的外部库,如下所示:

public delegate void processEvent(string deviceType, string deviceId,string evtName, string format, string data);
        // event for event callback
        public event processEvent eventCallback;

在我的代码中,我以这种方式订阅此事件

app.eventCallback += ProcessEvent;
    protected void ProcessEvent(string deviceType, string deviceId, string eventName, string format, string data)
{
            var requests = GetRequests();
            foreach (var serviceRequest in requests)
        {   
            client.callAsync(serviceRequest)
        }
}

问题是如何调用client.callAsync异步?我无法改变ProcessEvent的签名返回任务从那时起我无法将它绑定到eventCallback += ProcessEvent;

callAsync是异步方法

我应该创建任务列表然后等待全部还是有更好的方法?

c#
2个回答
2
投票

只需将async添加到方法签名:

 protected async void ProcessEvent(string deviceType, string deviceId, string eventName, string format, string data)

这是有效的,因为您没有更改返回类型。然后将呼叫更改为:

await client.callAsync(serviceRequest);

可能也想在这里使用ConfigureAwait(false)

如果要一次性异步运行所有服务请求,请将foreach更改为:

await Task.WhenAll(requests.Select(x => client.callAsync(x));

或者,如果需要,您可以使用任务集合。同样的效果。

写完后,您的事件处理程序一次只能执行一个请求。

如果你想阻止每个Task完成你可以这样做(这不需要异步或等待):

Task.WhenAll(requests.Select(x => client.callAsync(x)).Wait();

虽然它们听起来很相似,但awaitTask.Wait在概念上却是非常不同的东西。简而言之,前者是非阻塞的,后者是阻塞的。


1
投票

如果您需要等到所有任务完成才返回,那么我认为没有比创建任务列表和等待所有任务更好的方法了。例如。

Task.WaitAll(requests.Select(x => Task.Run(async (x) => await client.callAsync(x)));

上面的代码将在一个单独的线程上运行每个任务,然后阻塞主线程直到所有这些结束。

© www.soinside.com 2019 - 2024. All rights reserved.