我试图了解可用的并发方法,并试图了解哪种方法更适合我的当前情况。我的工作是获取URL列表的状态,无论它们同时返回HTTPStatus OK
还是Not OK
,限制线程数,并确保所提供的最大线程始终运行所有时间,而与批处理线程无关执行。为此,我尝试使用Task Parallel Library,并且工作正常。
代码
var parallelOptions = new ParallelOptions
{
MaxDegreeOfParallelism = 3
};
Parallel.ForEach(ListMonitorUrl, parallelOptions, i =>
{
LogMailError("URL: " + i.URL + " DateTime: " + DateTime.Now + " Thread ID: " + Thread.CurrentThread.ManagedThreadId, LogFile);
VerifyWebAppUrl(i);
});
public MonitorURLs VerifyWebAppUrl(MonitorURLs Model)
{
List<string> UrlsWithNotOKResponse = new List<string>();
try
{
var request = (HttpWebRequest)WebRequest.Create(Model.URL);
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
if (response.StatusCode != HttpStatusCode.OK && Model.Status == "A")
Model.ChangeOfStatus = true;
if (response.StatusCode == HttpStatusCode.OK && Model.Status != "A")
Model.ChangeOfStatus = true;
}
}
catch (Exception ex)
{
Model.ChangeOfStatus = false;
}
return Model;
}
我已经看到还有其他方法,例如SemaphoreSlim
,Task
。但是我不确定哪个最适合我的情况。请提出建议。
答案 0 :(得分:2)
Parallel.ForEach
完全不适合 IO绑定工作负载,您正在用尽宝贵的资源等待 IO完成端口,并限制了默认任务计划程序 / 线程池(这不仅会不必要地造成瓶颈,还会使应用程序的其他部分饿死)。
正确的方法将是支持异步等待模式的东西,例如Task.WhenAll
,响应式扩展, TPL DataFlow ,
这是一个简单的Microsoft TPL DataFlow 示例。您可以在这里System.Threading.Tasks.Dataflow
优点是
Parallel.ForEach
大得多)示例
public async List<Model> GetDeadUrls(List<Model> models)
{
var action = new ActionBlock<Model>(
// your async method
model => VerifyWebAppUrl(model),
//some options
new ExecutionDataflowBlockOptions()
{
// CancellationToken = sometoken,
// pick as many as your system can handle
MaxDegreeOfParallelism = 100,
// doesn't need to be ordered
EnsureOrdered = false,
// slight performance tweak, there is only one
SingleProducerConstrained = true
});
// start
foreach (var model in models)
action.Post(model);
// mark it as completed
action.Complete();
// wait for it to finish
await action.Completion;
// filter the results
return models.Where(x => x.ChangeOfStatus).ToList();
}
异步方法
public async Task<Model> VerifyWebAppUrl(Model model)
{
try
{
var request = (HttpWebRequest)WebRequest.Create(model.URL);
using (var response = (HttpWebResponse) await request.GetResponseAsync())
{
if (response.StatusCode != HttpStatusCode.OK && model.Status == "A")
model.ChangeOfStatus = true;
if (response.StatusCode == HttpStatusCode.OK && model.Status != "A")
model.ChangeOfStatus = true;
}
}
catch (Exception ex)
{
// this looks suspicious
model.ChangeOfStatus = false;
}
return model;
}
注意 :这完全未经测试,仅是一个示例