具有有序结果的异步多个 Web 服务请求

Asynchronous multiple Web Service requests with ordered result

给定一定数量的请求对象(最多 9 个),我需要异步调用相同次数的 Web 服务端点。对于 .NET 4.0,我们使用 delegateIAsyncResult 来实现这一点。

使用 asyc/awaitTPL 或两者结合 .NET 4.6.1 是否有更好的方法?

Parallel.ForEachConcurrentBag 结合使用是否会如本 answer 中所建议的那样最佳?

同步代码示例:

public List<WbsResponse> GetWbsResults()
{
    List<WbsRequest> requests = CompileWbsRequests();
    List<WbsResponse> results = new List<WbsResponse>();
    foreach (var request in requests)
    {
        //Call same web service endpoint n number of times
        var response = CallWebService(request);
        results.Add(response);
    }

    //do something with results

    return results;
}

private WbsResponse CallWebService(WbsRequest request)
{
    //Call web service
}

Edit/Update 1:根据@Thierry 的回答,我创建了一个示例代码,假设两者都有 Order 属性标记 request/response 排序的请求和响应对象:

public List<WbsResponse> GetWbsResults()    
{        
    List<WbsRequest> requests = CompileWbsRequests();
    List<WbsResponse> results = new List<WbsResponse>();

    Parallel.ForEach(requests, (request) => {
        var response = CallWebService(request);
        response.Order = request.Order;
        results.Add(response);
    });

    results = results.OrderBy(r => r.Order).ToList();

    //do something with results

    return results;
}

private WbsResponse CallWebService(WbsRequest request)
{
    //Call web service
}

Edit/Update 2:基于 this 线程,我对更新 1 做了一些更改:

await Task.Run(() => {
    Parallel.ForEach(requests, (request) => {
        var response = CallWebService(request);
        response.Order = request.Order;
        results.Add(response);
    });
});

要求摘要:

我认为您可以使用 Task.WaitAll 使代码以异步方式工作,它看起来也会更漂亮:

public List<WbsResponse> GetWbsResults()
{
    List<WbsRequest> requests = CompileWbsRequests();
    var responses = await Task.WhenAll(requests.Select(CallWebService));
    return responses;
}

但是您必须如下修改此方法以return一个任务:

private async Task<WbsResponse> CallWebService(WbsRequest request)
{
    //Call web service
}

因为每个任务在不同时刻完成,我认为你应该对请求进行编号,并按此编号对响应进行排序。

在请求中,您初始化一个数字并将此数字传递给关联的响应。最后,当我得到结果时,我就下单了。 像这样:

    public async Task<List<WbsResponse>> GetWbsResults()
    {
        List<WbsRequest> requests = CompileWbsRequests();
        List<Task<WbsResponse>> tasks = new List<Task<WbsResponse>>();
        for (var i = 0; i < requests.Count; i++)
        {
            var task = new Task<WbsResponse>(() => { CallWebService(WbsRequest); });
            tasks.Add(task);
        }
        var responses = await Task.WhenAll(tasks);

        var responsesOrdered = responses.OrderBy(r => r.Order)

        //do something with results

        return results;
    }  



    public List<WbsRequest> CompileWbsRequests()
    {
        //create requests
        foreach(var request in requests)
        {
            request.Order += 1;
        }
    }


    private WbsResponse CallWebService(WbsRequest request)
    {
        //Call web service

        reponse.order = request.order;
        return reponse;
    }