繁体   English   中英

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

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

我需要多次调用Web服务来获取数据,然后将这些数据放入数据库中,因此我得到了以下代码:

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

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;
}

我想将此代码修改为异步版本,以便在单独的线程中运行每个下载/保存到数据库的操作,并等待所有线程完成,或者也许有其他方法可以改善此类代码的性能,请您帮忙我?

为了提高可伸缩性(即,您的Web应用程序可以同时处理的请求数),您需要减少应用程序为每个请求使用的线程数。 因此, 与其等待所有线程完成 ,不如使用自然的异步API,这些API在操作挂起时不会阻塞线程。 可以在这里找到更多详细信息。

如果可以使用.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;
}

对于客户端代理WsClient可能已经有一个异步版本getNodes ,称为getNodesAsync (如果没有,检查这个 )。 ProcessDataAsync (针对每个节点)启动一堆并行的非阻塞GetDataAsync任务,并异步等待其完成。 这就是使此代码可扩展的原因。

你也许能够进一步提高ProcessDataAsync通过异步地保存数据,即await _dbService.SaveToDbAsync(nodes) ,如果你可以利用使用异步的Task为基础的DB API(例如, EF6 )。

这将并行下载所有文件,并将它们一次写入就存储到数据库中。

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

这将启动异步调用

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

这将等待执行完成并返回值:

IList<MySampleNode> result=asyncSearchResult EndInvoke();

暂无
暂无

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

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