简体   繁体   English

异步调用Webservice并等待所有线程完成

[英]Call webservice asynchronously and wait for all threads to be finished

I need to call the web service several times to get data, and then put those data into my database, so I've got the following code: 我需要多次调用Web服务来获取数据,然后将这些数据放入数据库中,因此我得到了以下代码:

foreach (string v in options)
{
    IList<MySampleNode> nodes = _pi.GetData(v);
    _dbService.SaveToDb(nodes);
}

the GetData implementation looks as follows: GetData实现如下所示:

public IList<MySampleNode> GetData(string v)
{
    IList<MySampleNode> nodes = null;
    try
    {
        var client = new WsClient();
        IEnumerable<IWsObject> wsNodes = client.getNodes(new getClassLevel { code = v });
        nodes = ProcessData(wsNodes);
    }
    return nodes;
}

I'd like to modify this code to asynchronous version to run each download/save to database in separate thread and wait for all threads to be finished, or maybe there are some other approaches to improve the performance of such code, can you please help me? 我想将此代码修改为异步版本,以便在单独的线程中运行每个下载/保存到数据库的操作,并等待所有线程完成,或者也许有其他方法可以改善此类代码的性能,请您帮忙我?

To improve the scalability (ie, the number of request your web app can serve simultaneously), you need to reduce the number of threads your app is using for each requests. 为了提高可伸缩性(即,您的Web应用程序可以同时处理的请求数),您需要减少应用程序为每个请求使用的线程数。 So, instead of waiting for all threads to be finished , you should use naturally asynchronous APIs, which don't block a thread while the operation is pending. 因此, 与其等待所有线程完成 ,不如使用自然的异步API,这些API在操作挂起时不会阻塞线程。 More details on this can be found here . 可以在这里找到更多详细信息。

If you can use .NET 4.5, your specific case might be improved like this: 如果可以使用.NET 4.5,则您的特定情况可能会得到改善,如下所示:

public void Page_Load(object sender, EventArgs e)
{
    RegisterAsyncTask(new PageAsyncTask(ProcessDataAsync));
}

public async Task ProcessDataAsync()
{
    var tasks = options.Select(v => _pi.GetDataAsync(v));
    await Task.WhenAll(tasks);
    var nodes = tasks.Select(t => t.Result);
    _dbService.SaveToDb(nodes);
}

public async Task<IList<MySampleNode>> GetDataAsync(string v)
{
    IList<MySampleNode> nodes = null;
    using (var client = new WsClient())
    {
        IEnumerable<IWsObject> wsNodes = 
            await client.getNodesAsync(new getClassLevel { code = v });
        nodes = ProcessData(wsNodes);
    }
    return nodes;
}

The client-side proxy for WsClient probably already has an async version of getNodes , called getNodesAsync (if not, check this ). 对于客户端代理WsClient可能已经有一个异步版本getNodes ,称为getNodesAsync (如果没有,检查这个 )。 ProcessDataAsync starts a bunch of parallel non-blocking GetDataAsync tasks (for each node), and asynchronously awaits their completion. ProcessDataAsync (针对每个节点)启动一堆并行的非阻塞GetDataAsync任务,并异步等待其完成。 That's what makes this code scale well. 这就是使此代码可扩展的原因。

You might be able to further improve ProcessDataAsync by saving the data asynchronously, ie await _dbService.SaveToDbAsync(nodes) , if you can leverage the use of asynchronous Task -based DB API (eg, with EF6 ). 你也许能够进一步提高ProcessDataAsync通过异步地保存数据,即await _dbService.SaveToDbAsync(nodes) ,如果你可以利用使用异步的Task为基础的DB API(例如, EF6 )。

This downloads all in parallel and stores them into the DB with one write. 这将并行下载所有文件,并将它们一次写入就存储到数据库中。

var tasks = options.Select(o => Task.Run(() => GetData(o)));
Task.WaitAll(tasks.ToArray());
var nodes = tasks.SelectMany(t => t.Result);
_dbService.SaveToDb(nodes);

This would initiate asynchronous call 这将启动异步调用

 public delegate IList<MySampleNode> SaveToDb(IList<MySampleNode> myParam);
 SaveToDb _saveToDb= new SaveToDb(objService.SaveToDb);
 IAsyncResult asyncSearchResult = saveToDb.BeginInvoke(input,null,null)

This would wait for execution to complete and return value:- 这将等待执行完成并返回值:

IList<MySampleNode> result=asyncSearchResult EndInvoke();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM