【发布时间】:2019-12-24 01:26:33
【问题描述】:
我想并行调用一个异步方法大约 1000 次。
我有一个大约 10000 行的数据表。我想比较它的两行,如果某些条件为真,则调用异步方法。总的来说,这个方法(GetApiData())可能被调用了大约 1000 次。我读了几篇文章,写了一些代码。我的简化代码是:
public static HttpClientHandler httpClientHandler = new HttpClientHandler()
private static HttpClient Client = new HttpClient(handler: httpClientHandler, disposeHandler: true) { MaxResponseContentBufferSize = 10000000 };
private Button1_Click(Object sender, EventArgs e)
{
httpClientHandler.Proxy = null;
httpClientHandler.UseProxy = false;
await DoWork();
}
public async Task DoWork()
{
var allTasks = new List<Task>();
for (int i = 0; i < dt.Rows.Count; i++)
{
if(Some condition)
allTasks.Add(Task.Run(() => GetApiData()));
}
Task waitAll = Task.WhenAll(allTasks);
await waitAll;
}
public async Task GetApiData()
{
var Result= await (await Client.GetAsync("Some Url")).Content.ReadAsStringAsync();
//do some cpu bound(but not too heavy, like search in a datatable that have 20 rows) work on Result.
}
这段代码对我有用,但我认为它花费了太多时间。我有一些问题: 1-我的代码是并行的。如果不是我该怎么做。当我将断点设置为“Task waitAll = Task.WhenAll(allTasks);”时线,到达这条线需要太长时间,所以我认为我的代码不是并行的(我知道任务在创建后运行)。 2- 我需要在数据表中写入一些数据来改进我的代码,但我知道数据表不是线程安全的。有没有一种简单的方法可以将数据表转换为线程安全的数据结构。 3-我认为我的代码受 I/O 限制但是,如果我准备一台具有更多内核(如服务器)的计算机,例如 24 核和 48 线程,这是否会减少我的代码时间。谢谢。
【问题讨论】:
-
我找不到它,但我很确定单个
HttpClient存在硬性限制。但至于并行性,您的代码似乎是正确的。您启动所有查询并以正确的方式等待所有查询完成。Datatable是一个简单的结构。每行是一个类,每列有 1 个属性。使用自定义类创建线程友好的集合。对于测试,您可以使用object[]来包含这些值。是的,它是装箱/拆箱,但对于概念验证来说就足够了。准备好后,让它成为一个适当的类,你会很好去 -
@Franck,感谢您的回答。您的“单个 HttpClient 有硬性限制”的意思是什么。你会建议有几个 HttpClient 吗?如果我可以将我的数据表(或线程友好的集合)分成几个数据表并以并行模式运行每个数据表,这种情况是否可以减少我的代码时间。
-
我不是 100% 确定,但我认为一旦你有 25 个查询出来,在至少有一个得到回应之前,没有其他人可以出去。不要把它当成事实,我只知道过去有这种限制,当我做很多查询时,解决方案就像拥有更多 HttpClient 对象一样简单。
-
@Franck 谢谢,您关于单个 HttpClient 硬限制的提示节省了我的时间。
标签: c# .net parallel-processing async-await parallel.foreach