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

时间:2014-01-26 21:29:46

标签: c# asp.net multithreading web-services asynchronous

我需要多次调用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;
}

我想将此代码修改为异步版本以在单独的线程中运行每次下载/保存到数据库并等待所有线程完成,或者可能还有其他一些方法来提高此类代码的性能,可以你能帮帮我吗?

3 个答案:

答案 0 :(得分:1)

要提高可伸缩性(即,您的Web应用可以同时提供的请求数),您需要减少应用为每个请求使用的线程数。因此,代替等待所有线程完成,您应该使用自然异步API,这些API在操作挂起时不会阻塞线程。有关详细信息,请参见here

如果您可以使用.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(如果没有,请检查this)。 ProcessDataAsync启动一堆并行的非阻塞GetDataAsync任务(对于每个节点),并异步等待它们完成。这就是使这个代码很好地扩展的原因。

如果可以利用基于异步ProcessDataAsync的异步数据库API(例如,使用{{},则可以通过异步保存数据(即await _dbService.SaveToDbAsync(nodes))来进一步改进Task。 {3}})。

答案 1 :(得分:0)

全部并行下载并通过一次写入将它们存储到DB中。

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

答案 2 :(得分:0)

这将启动异步调用

 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();