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



我需要多次调用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,它不会在操作挂起时阻塞线程。有关这方面的更多详细信息,请点击此处。

如果你可以使用.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的客户端代理可能已经有一个名为getNodesAsyncgetNodes异步版本(如果没有,请检查此项)。ProcessDataAsync启动一组并行的无阻塞GetDataAsync任务(针对每个节点),并异步等待它们的完成。这就是这个代码能够很好地扩展的原因。

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

这将并行下载所有内容,并通过一次写入将它们存储到DB中。

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

最新更新