【问题标题】:Call webservice asynchronously and wait for all threads to be finished异步调用webservice,等待所有线程完成
【发布时间】:2014-01-28 08:54:30
【问题描述】:

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

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

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

【问题讨论】:

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

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


【解决方案1】:

为了提高可扩展性(即,您的网络应用可以同时处理的请求数量),您需要减少应用为每个请求使用的线程数。因此,您应该使用自然的异步 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 任务(针对每个节点),并异步等待它们完成。这就是使此代码能够很好地扩展的原因。

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      这将启动异步调用

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

      【讨论】:

        猜你喜欢
        • 2016-03-16
        • 2011-10-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-02-22
        • 1970-01-01
        • 1970-01-01
        • 2016-07-07
        相关资源
        最近更新 更多