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

C# 异步调用webservice并等待所有线程完成,c#,asp.net,multithreading,web-services,asynchronous,C#,Asp.net,Multithreading,Web Services,Asynchronous,我需要多次调用web服务来获取数据,然后将这些数据放入我的数据库,因此我得到了以下代码: foreach (string v in options) { IList<MySampleNode> nodes = _pi.GetData(v); _dbService.SaveToDb(nodes); } foreach(选项中的字符串v) { IList节点=_pi.GetData(v); _dbService.SaveToDb(节点); } GetData实现如下所

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

foreach (string v in options)
{
    IList<MySampleNode> nodes = _pi.GetData(v);
    _dbService.SaveToDb(nodes);
}
foreach(选项中的字符串v)
{
IList节点=_pi.GetData(v);
_dbService.SaveToDb(节点);
}
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;
}
public IList GetData(字符串v)
{
IList节点=null;
尝试
{
var client=new WsClient();
IEnumerable wsNodes=client.getNodes(新的getClassLevel{code=v});
节点=ProcessData(wsNodes);
}
返回节点;
}

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

这将并行下载所有代码,并通过一次写入将它们存储到数据库中

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

为了提高可伸缩性(即web应用程序可以同时服务的请求数),您需要减少应用程序用于每个请求的线程数。因此,您不应该等待所有线程完成,而应该使用自然异步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;
}
public void页面加载(对象发送方,事件参数e)
{
RegisterAsyncTask(新页面异步任务(ProcessDataAsync));
}
公共异步任务ProcessDataAsync()
{
var tasks=options.Select(v=>pi.GetDataAsync(v));
等待任务。何时(任务);
var nodes=tasks.Select(t=>t.Result);
_dbService.SaveToDb(节点);
}
公共异步任务GetDataAsync(字符串v)
{
IList节点=null;
使用(var client=new WsClient())
{
IEnumerable wsNodes=
等待client.getNodesAsync(新的getClassLevel{code=v});
节点=ProcessData(wsNodes);
}
返回节点;
}
WsClient
的客户端代理可能已经有一个异步版本的
getNodes
,名为
getNodesAsync
(如果没有,请检查)
ProcessDataAsync
启动一系列并行非阻塞
GetDataAsync
任务(针对每个节点),并异步等待其完成。这就是为什么这段代码能够很好地扩展


如果您可以利用基于异步
任务
的DB API(例如,with)的使用,则可以通过异步保存数据,即
wait\u dbService.SaveToDbAsync(节点)
,进一步改进
ProcessDataAsync

这将启动异步调用

 public delegate IList<MySampleNode> SaveToDb(IList<MySampleNode> myParam);
 SaveToDb _saveToDb= new SaveToDb(objService.SaveToDb);
 IAsyncResult asyncSearchResult = saveToDb.BeginInvoke(input,null,null)
公共委托IList SaveToDb(IList myParam);
SaveToDb\u SaveToDb=newsavetodb(objService.SaveToDb);
IAsyncResult asyncSearchResult=saveToDb.BeginInvoke(输入,null,null)
这将等待执行完成并返回值:-

IList<MySampleNode> result=asyncSearchResult EndInvoke();
IList result=asyncSearchResult EndInvoke();

您使用的ASP.NET版本是什么?