C# 异步方法不能异步运行

C# 异步方法不能异步运行,c#,async-await,task-parallel-library,C#,Async Await,Task Parallel Library,我正在用WPF编写下面的代码。但是,它不会异步运行。我已经注释了代码被阻塞的那一行。请让我知道我在哪里犯错 private async void txtSamplerRequest\u单击(对象发送方,RoutedEventArgs e) { 等待下载数据(); } 异步任务下载数据() { 字符串授权=txtAuthentication.Text; 字符串cookie=txtCookie.Text; 尝试 { var vvv=可枚举范围(0,50); List TaskList=新列表();

我正在用WPF编写下面的代码。但是,它不会异步运行。我已经注释了代码被阻塞的那一行。请让我知道我在哪里犯错

private async void txtSamplerRequest\u单击(对象发送方,RoutedEventArgs e)
{
等待下载数据();
}
异步任务下载数据()
{
字符串授权=txtAuthentication.Text;
字符串cookie=txtCookie.Text;
尝试
{
var vvv=可枚举范围(0,50);
List TaskList=新列表();
foreach(在vvv中的int s)
{
Task LastTask=ZerodhaOperations.MyHttpRequest(“,authorization,cookie,“5minute”);//即使这个方法是异步方法,我也添加了dummy Task.Delay(1)来异步运行这个方法。下面是这个类的完整定义。
任务列表。添加(上一个任务);
}
wait Task.WhenAll(TaskList);//是指它在异步产生时捕获一个“上下文”。详细信息在链接中,但在本例中,异步方法在WPF UI线程上运行,因此它捕获一个将在该UI线程上恢复运行的上下文

因此,
等待任务。延迟(1)
实际上是在强迫
MyHttpRequest
异步运行,但接下来发生的事情会让你大吃一惊。
MyHttpRequest
是否等待
,它捕获UI上下文并返回一个不完整的任务。这会在
下载数据
中多次发生,它收集不完整的任务,然后
wait
s
任务。当所有
任务都执行时。因此
DownloadData
返回一个未完成的任务,该任务被事件处理程序
wait
调用,事件处理程序将控制权返回给WPF消息循环

现在,接下来发生的事情是那些
Task.Delay
计时器几乎立即启动。因此,
MyHttpRequest
恢复其
async
方法,并且由于其
wait
捕获了该UI上下文,它恢复在UI线程上运行。因此
wait Task.Delay(1)
确实导致了WPF消息循环的屈服,但实际上,UI线程接下来要做的就是恢复那些
异步
方法

其余的
async
方法是同步的,阻塞了UI线程

因此,要解决这个问题,您可以使这些方法真正异步。完全删除
等待任务。延迟(1)
,用异步API替换同步API(
GetResponseAsync
ReadToEndAsync
)。或者,如果要进一步更新代码,请将
WebRequest
替换为
HttpClient

另一个选项是保持代码同步,只需使用
任务。运行
在后台线程上运行同步代码。同样,您将删除
等待任务。延迟(1)
,这次您将更改方法签名为同步。然后您可以将调用包装为(同步)
MyHttpRequest
Task.Run
中,例如
Task LastTask=Task.Run(()=>ZerodhaOperations.MyHttpRequest(“,授权,cookie,“5分钟”))
Task.Run
解决方案不如异步解决方案理想,但是如果您还有很多其他代码需要同步,那么它是可以接受的


请注意,无论哪种方式,
Task.Delay(1)
的使用都是错误的。它不会“异步运行[the]方法”。异步运行方法的正确方式是让它调用异步API,而不是调用阻塞API。

您不会使用异步代码的好处。
Task.Delay(1)
很快就会注意到,在代码同步之后。使
任务延迟(5000)
查看UI在5秒钟内没有被阻止。但是在那之后,
任务。延迟
您的代码是同步的,并且会阻止UI。相反,使用异步方法从web服务检索数据。鼓轮滚动…您的HttpRequest是同步的!我已经很久没有使用
WebRequest
了,但是如果它们有
async
方法的话但是,您应该真正使用
IHttpClientFactory
并完成it@MichałTurczyn-
async void
对于UI控件,事件处理程序完全可以使用,异常将正确抛出。但是您当然应该切换到HttpClient并使用其异步方法。