joh*_* Gu 2 .net c# asp.net parallel-processing asp.net-mvc
我正在开发一个asp.net MVC-5 Web应用程序,基于我读过的一些文章,我不应该在Web服务器和.net web应用程序中使用并行方法.现在在我的情况下WebClient(),我需要在foreach中发出大约1,500个调用,然后从WebClient()调用中反序列化返回的json对象.使用前的原始代码Parallel.Foreach如下,大约需要15分钟才能完成: -
public async Task <List<Details2>> Get()
{
try
{
using (WebClient wc = new WebClient())
{
string url = currentURL + "resources?AUTHTOKEN=" + pmtoken;
var json = await wc.DownloadStringTaskAsync(url);
resourcesinfo = JsonConvert.DeserializeObject<ResourcesInfo>(json);
}
ForEach( var c in resourcesinfo.operation.Details)
{
ResourceAccountListInfo resourceAccountListInfo = new ResourceAccountListInfo();
using (WebClient wc = new WebClient())
{
string url = currentURL + "resources/" + c.RESOURCEID + "/accounts?AUTHTOKEN=" + pmtoken;
string tempurl = url.Trim();
var json = await wc.DownloadStringTaskAsync(tempurl);
resourceAccountListInfo = JsonConvert.DeserializeObject<ResourceAccountListInfo>(json);
}
if (resourceAccountListInfo.operation.Details.CUSTOMFIELD.Count > 0)
{
List<CUSTOMFIELD> customfield = resourceAccountListInfo.operation.Details.CUSTOMFIELD.Where(a =>
a.CUSTOMFIELDLABEL.ToLower() == "name"
).ToList();
if (customfield.Count == 1)
{
PMresourcesOnly.Add(resourceAccountListInfo.operation.Details);
}
}
}//end of foreach
return PMresourcesOnly.ToList();
}
catch (Exception e)
{
}
return new List<Details2>();
}
Run Code Online (Sandbox Code Playgroud)
现在我做了以下修改: -
foreach用Parallel.ForEach 因为我不应该使用内异步方法Parallel.ForEach,所以我chnage的DownloadStringTaskAsync到 DownloadString里面的Parallel.Foreach: -
public async Task <List<Details2>> Get()
{
try
{
using (WebClient wc = new WebClient())
{
string url = currentURL + "resources?AUTHTOKEN=" + pmtoken;
var json = await wc.DownloadStringTaskAsync(url);
resourcesinfo = JsonConvert.DeserializeObject<ResourcesInfo>(json);
}
Parallel.ForEach(resourcesinfo.operation.Details, new ParallelOptions { MaxDegreeOfParallelism = 7 }, (c) =>
{
ResourceAccountListInfo resourceAccountListInfo = new ResourceAccountListInfo();
using (WebClient wc = new WebClient())
{
string url = currentURL + "resources/" + c.RESOURCEID + "/accounts?AUTHTOKEN=" + pmtoken;
string tempurl = url.Trim();
var json = wc.DownloadString(tempurl);
resourceAccountListInfo = JsonConvert.DeserializeObject<ResourceAccountListInfo>(json);
}
if (resourceAccountListInfo.operation.Details.CUSTOMFIELD.Count > 0)
{
List<CUSTOMFIELD> customfield = resourceAccountListInfo.operation.Details.CUSTOMFIELD.Where(a =>
a.CUSTOMFIELDLABEL.ToLower() == "name"
).ToList();
if (customfield.Count == 1)
{
PMresourcesOnly.Add(resourceAccountListInfo.operation.Details);
}
}
});//end of foreach
return PMresourcesOnly.ToList();
}
catch (Exception e)
{
}
return new List<Details2>();
}
Run Code Online (Sandbox Code Playgroud)现在当我使用时,Parallel.Foreach执行时间从15分钟减少到大约7分钟.但如果我的第二种方法有效,我会有点困惑,所以任何人都可以对这些问题(或任何问题)进行思考: -
是使用Parallel.Foreach带有Webclient()一种有效的方法可循?或者我应该避免在.net和Web应用程序中使用Parallel方法?
在使用时Parallel.Foreach我是否可以面对任何问题,例如return PMresourcesOnly.ToList();返回客户端,而仍有一些wc.DownloadString(tempurl);没有完成?
如果我想比较2种方法(Parallel.Foreach&Foreach),结果是否相同?
在他们使用的一些在线文章Task.Factory.StartNew(()而不是使用Parallel.foreach它们之间有什么主要区别?
编辑
我尝试定义SemaphoreSlim如下: -
public async Task <List<Details2>> Get()
{
SemaphoreSlim throttler = new SemaphoreSlim(initialCount: 15);
try
{
//code goes here
var tasks = resourcesinfo.operation.Details.Select(c => TryDownloadResourceAsync(c.RESOURCEID,throttler)).ToList();
}
Run Code Online (Sandbox Code Playgroud)
/// ---
private async Task<Details2> TryDownloadResourceAsync(string resourceId, SemaphoreSlim throttler)
{
await throttler.WaitAsync();
try
{
using (WebClient wc = new WebClient()) //get the tag , to check if there is a server with the same name & tag..
{}
}
finally
{
throttler.Release();
}
Run Code Online (Sandbox Code Playgroud)
正在使用Parallel.Foreach和Webclient()一个有效的方法来遵循?或者我应该避免在.net和Web应用程序中使用Parallel方法?
不,你绝对应该避免在ASP.NET应用程序中使用并行方法.
在一些在线文章中,他们使用Task.Factory.StartNew(()而不是使用Parallel.foreach,那么它们之间的主要区别是什么?
Parallel用于数据并行(在数据项集合上运行相同的CPU绑定代码).StartNew用于动态任务并行(在处理它时更改的项集合上运行相同或不同的CPU绑定代码).
这两种方法都不合适,因为您需要做的工作是I/O绑定,而不是CPU绑定.
你真正想要的是并发性(一次做多件事),而不是并行性.而不是使用并行并发(通过使用多个线程一次做多个事情),你想要的是异步并发(使用无线程一次做多件事).
代码中的异步并发是可能的await Task.WhenAll,因此:
private async Task<string> 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<ResourceAccountListInfo>(json);
}
if (resourceAccountListInfo.operation.Details.CUSTOMFIELD.Count > 0)
{
List<CUSTOMFIELD> 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 <List<Details2>> Get()
{
try
{
using (WebClient wc = new WebClient())
{
string url = currentURL + "resources?AUTHTOKEN=" + pmtoken;
var json = await wc.DownloadStringTaskAsync(url);
resourcesinfo = JsonConvert.DeserializeObject<ResourcesInfo>(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<Details2>(); // Please, please don't do this in production.
}
Run Code Online (Sandbox Code Playgroud)
最后要注意的是,您可能需要研究一下HttpClient,这是为异步操作而设计的,并且具有良好的属性,您只需要其中一个用于任意数量的同时调用.
| 归档时间: |
|
| 查看次数: |
1567 次 |
| 最近记录: |