are there any drawbacks or risks of using Parallel.Foreach with WebClient() inside my asp.net mvc web application

后端 未结 2 806
被撕碎了的回忆
被撕碎了的回忆 2021-02-11 02:52

I am working on an asp.net MVC-5 web application, and based on some articles i read that i should not use Parallel methods inside web servers and inside .net web applications es

2条回答
  •  攒了一身酷
    2021-02-11 03:57

    is using Parallel.Foreach with Webclient() a valid approach to follow ? or i should avoid using Parallel methods inside .net and web applications?

    No, you absolutely should avoid using parallel methods inside ASP.NET apps.

    on some online articles they use Task.Factory.StartNew(() instead of using Parallel.foreach so what are the main differences between them ?

    Parallel is for data parallism (running the same CPU-bound code over a collection of data items). StartNew is for dynamic task parallelism (running the same or different CPU-bound code over a collection of items that changes as you process it).

    Neither approach is appropriate here, since the work you have to do is I/O-bound, not CPU-bound.

    What you actually want is concurrency (doing multiple things at a time), not parallelism. Instead of using parallel concurrency (doing multiple things at a time by using multiple threads), what you want is asynchronous concurrency (doing multiple things at a time using no threads).

    Asynchronous concurrency is possible in code via await Task.WhenAll, as such:

    private async Task TryDownloadResourceAsync(string resourceId)
    {
      ResourceAccountListInfo resourceAccountListInfo = new ResourceAccountListInfo();
      using (WebClient wc = new WebClient()) 
      {
        string url = currentURL + "resources/" + resourceId + "/accounts?AUTHTOKEN=" + pmtoken;
        string tempurl = url.Trim();
    
        var json =  await wc.DownloadStringTaskAsync(tempurl);
        resourceAccountListInfo = JsonConvert.DeserializeObject(json);
      }
    
      if (resourceAccountListInfo.operation.Details.CUSTOMFIELD.Count > 0)
      {
        List customfield = resourceAccountListInfo.operation.Details.CUSTOMFIELD.Where(a =>
            a.CUSTOMFIELDLABEL.ToLower() == "name"
        ).ToList();
        if (customfield.Count == 1)
        {
          return resourceAccountListInfo.operation.Details;
        }
      }
      return null;
    }
    
    public async Task > Get()
    {       
      try
      {
        using (WebClient wc = new WebClient()) 
        {
          string url = currentURL + "resources?AUTHTOKEN=" + pmtoken;
          var json = await wc.DownloadStringTaskAsync(url);
          resourcesinfo = JsonConvert.DeserializeObject(json);
        }
    
        var tasks = resourcesinfo.operation.Details.Select(c => TryDownloadResourceAsync(c.RESOURCEID)).ToList();
        var results = await Task.WhenAll(tasks).Select(x => x != null);
        return results.ToList();
      }
      catch (Exception e)
      {
      }
      return new List(); // Please, please don't do this in production.
    }
    

    As a final note, you may want to look into HttpClient, which was designed for asynchronous operations and has the nice property that you only need one of them for any number of simultaneous calls.

提交回复
热议问题