C# Task.WaitAll保持循环
我尝试此异步代码只是为了测试async关键字:C# Task.WaitAll保持循环,c#,async-await,C#,Async Await,我尝试此异步代码只是为了测试async关键字: public async Task<string> AsyncMethod() { var link = "http://www.google.com"; var webclient = new WebClient(); var result = await webclient.DownloadStringTaskAsync(new Uri(link)); return result; } publ
public async Task<string> AsyncMethod()
{
var link = "http://www.google.com";
var webclient = new WebClient();
var result = await webclient.DownloadStringTaskAsync(new Uri(link));
return result;
}
public async Task<ActionResult> Index()
{
var a = AsyncMethod();
var b = AsyncMethod();
Task.WaitAll(a, b);
return View();
}
公共异步任务AsyncMethod()
{
变量链接=”http://www.google.com";
var webclient=新的webclient();
var result=await-webclient.downloadstringtasksync(新Uri(链接));
返回结果;
}
公共异步任务索引()
{
var a=AsyncMethod();
var b=AsyncMethod();
Task.WaitAll(a,b);
返回视图();
}
但是当我调试它时,调试器会点击任务.WaitAll
而什么也不做(return键从未执行过)。。
如果我在两个'AsyncMethod'之前设置wait并删除Task.WaitAll
它会工作。。那么我做错了什么呢?它是这样工作的:
public Task<string> FakeAsyncMethod()
{
var link = "http://google.com";
var webclient = new WebClient();
var t = new Task<string>(() => webclient.DownloadString(new Uri(link)));
return t;
}
public async Task Index()
{
var a = FakeAsyncMethod();
var b = FakeAsyncMethod();
a.Start();
b.Start();
Task.WaitAll(a, b);
}
async void AsyncCall()
{
await Index();
}
因为您的方法看起来像ASP.NET MVC控制器操作,所以我假设您正在ASP.NET上运行 默认情况下,异步方法在其挂起的同一上下文(即调用
wait
)上恢复。在ASP.NET中,这表示当前请求上下文。一次只能有一个线程处于特定上下文中。因此,执行Index()
的线程位于请求上下文中,被阻塞在WaitAll()
中。另一方面,asynchmethod()
的两个调用都试图在相同的上下文中恢复(下载完成后),但它们无法恢复,因为Index()
仍在该上下文中执行。正因为如此,这些方法处于一种状态,因此不会发生任何事情
(同样的死锁也会发生在GUI应用程序中,因为GUI上下文在这方面的行为类似。控制台应用程序没有这个问题,因为它们没有任何上下文。)
解决方法有两个:
异步
方法。(唯一的例外可能是希望从控制台应用程序的Main()
方法执行异步方法。)
相反,异步等待它们。在您的情况下,这意味着使用wait Task.whalll(a,b)
ConfigureAwait(false)
(即实际上不需要在请求上下文中执行的方法)
有关此问题的更多信息,请阅读Stephen Cleary的文章。WaitAll是否启动任务?如果没有,那么您将等待很长时间,因为没有人启动任务…@flq您所说的启动任务是什么意思?@flq由标记为
async
修饰符的方法返回的任务已在运行。您是否在返回结果处设置了断点?也许taks在开始任务之前就已经完成了。等等。在等待之后,试着打印结果,看看你是否得到了什么。还有一件事,你不需要在Index()中使用async关键字。我想它在任务完成之前还没有完成。WaitAll,下载不会这么快,如果我删除索引的async,我会遇到一个异常。我不明白为什么我需要启动async任务,因为当我在async方法中设置本地url时,我注意到页面已下载。太好了,这正是我需要的。谢谢。在我发布的第一个示例中,您使用的不是您的方法,而是我的方法(fakeasynchmethod
)。它返回一个任务,其状态
等于已创建
,但尚未运行--这就是您需要启动它的原因。在我的编辑中,您使用的是您的方法。这并不能解释实际问题是什么,也不能解释修复工作的原因。我不明白为什么让任务处于运行状态会是一个问题。非常有用,我注意到这个问题没有发生在控制台应用程序上,但我不知道为什么+1.
public async Task Index()
{
var a = AsyncMethod();
var b = AsyncMethod();
await Task.WhenAll(a, b);
}