und*_*ent 9 c# asynchronous task blocking async-await
我一直在努力学习C#与HttpClient的异步,并遇到了一个我无法弄清楚发生了什么的问题.
我想做的事:
问题:
每当我一起发送请求列表时,响应似乎要花费更长的时间,但它们应该大致相同.例如:
所用时间:67.9609毫秒所用
时间:89.2413毫秒所用
时间:100.2345毫秒所用
时间:117.7308毫秒所用
时间:127.6843毫秒所用
时间:132.3066毫秒所用
时间:157.3057毫秒
什么时候它们都应该只有70毫米左右...这对于每一批新产品都会重复; 第一个是快速的,然后每个连续的减速.
我的代码
有3个主要部分.我已经简化了它,我可以专注于问题发生的地方(Downloader.cs是我的时间)
Downloader.cs这包含执行实际http查询的方法:
public async Task<string> DownloadData(string requestString)
{
HttpResponseMessage response;
response = await this.httpClient.PostAsync( url, new StringContent( requestString ));
string returnString = await response.Content.ReadAsStringAsync();
return returnString;
}
Run Code Online (Sandbox Code Playgroud)QueryAgent.cs这初始化一个新的Downloader并包含主异步循环调用函数和它在循环中调用的异步方法.
我需要尽快发送新的请求,具体取决于最后一组响应的结果(基本上,请求发出的速率可能会发生变化,所以我不能在结束时执行Task.delay() while循环)
public async Task DownloadLoopAsync()
{
while ( this.isLooping )
{
// I put this here to stop it using lots of cpu.
// Not sure if it is best practice.
// advice on how to do this kind of loop would be appreciated.
await Task.Delay( 5 );
foreach ( string identifier in this.Identifiers )
{
string newRequestString = this.generateRequestString(identifier );
Task newRequest = RequestNewDataAsync(newRequestString);
}
}
}
public async Task RequestNewDataAsync(string requestString)
{
string responseString = await this.downloader.DownloadData(requestString);
this.ProcessedData = this.ProcessData(responseString);
}
Run Code Online (Sandbox Code Playgroud)Program.cs这只是一个控制台程序,它在QueryAgent中的异步函数上调用一次Task,然后在末尾调用Console.Readline()以停止程序退出.我也在这里初始化HttpClient.我称之为DownloadLoop()一次,如下:
QueryAgent myAgent = new QueryAgent(httpClient);
Task dataLoop = myAgent.DownloadLoopAsync();
Console.Readline();
Run Code Online (Sandbox Code Playgroud)我怀疑它与我在DownloadLoopAsync()中的for循环中调用新任务的方式有关,但是这没有意义,因为我假设每个新任务都将由它自己处理.
任何建议都非常感谢,因为我在砖墙试图按预期工作后一直打砖墙.
谢谢.
编辑1
在调用Task循环中乱七八糟.我变了:
foreach(string identifier in this.Identifiers)
{
string newRequestString = this.generateRequestString(identifier );
Task newRequest = RequestNewDataAsync(newRequestString);
}
Run Code Online (Sandbox Code Playgroud)
至
foreach(string identifier in this.Identifiers)
{
string newRequestString = this.generateRequestString(identifier );
Task newRequest = RequestNewDataAsync(newRequestString);
await Task.Delay(1);
}
Run Code Online (Sandbox Code Playgroud)
现在它按预期工作:
Time taken: 71.0088 milliseconds
Time taken: 65.0499 milliseconds
Time taken: 64.0955 milliseconds
Time taken: 64.4291 milliseconds
Time taken: 63.0841 milliseconds
Time taken: 64.9841 milliseconds
Time taken: 63.7261 milliseconds
Time taken: 66.451 milliseconds
Time taken: 62.4589 milliseconds
Time taken: 65.331 milliseconds
Time taken: 63.2761 milliseconds
Time taken: 69.7145 milliseconds
Time taken: 63.1238 milliseconds
Run Code Online (Sandbox Code Playgroud)
现在我更加困惑为什么这似乎有效!
编辑2
在Downloader.cs中,时序代码如下:
public async Task<string> DownloadData(string requestString)
{
HttpResponseMessage response;
Stopwatch s = Stopwatch.StartNew();
response = await this.httpClient.PostAsync( url, new StringContent( requestString ));
double timeTaken = s.Elapsed.TotalMilliseconds;
Console.WriteLine( "Time taken: {0} milliseconds", timeTaken );
string returnString = await response.Content.ReadAsStringAsync();
return returnString;
}
Run Code Online (Sandbox Code Playgroud)
虽然等待Task.Delay(1); 似乎"做的伎俩",它不是一个理想的解决方案,也不理解为什么它的工作 - 也许它以某种方式它给CPU时间初始化RequestNewDataAsync任务并防止某种类型的锁定同时发生?我只能猜测...这也意味着它将循环限制为1000Hz,这很快,但也是一个限制,因为Task.Delay()只接受整数值,其中1是最小值.
编辑3
多做一些阅读(我对这一切仍然相对较新!),也许这是使用Threadpool(10到100个短期任务)的最佳选择?但是这会产生过多的(每个新任务1MB?)开销; 或者是那种不同的东西.
编辑4
尝试将Task.Delay(1)放在不同的地方.
当你这样做时await,后续代码只有在你等待完成之后才会被执行.
要同时发送多个查询,您必须Task为每个查询创建新查询,然后等待所有查询.
var tasks = new List<Task>();
foreach (string identifier in Identifiers)
{
var newRequestString = generateRequestString(identifier);
var newRequest = RequestNewDataAsync(newRequestString);
tasks.Add(newRequest);
}
Task.WhenAll(tasks); // synchronous wait for all tasks to complete
Run Code Online (Sandbox Code Playgroud)