Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Task.WaitAll保持循环_C#_Async Await - Fatal编程技术网

C# Task.WaitAll保持循环

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

我尝试此异步代码只是为了测试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;
}

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)
    (即实际上不需要在请求上下文中执行的方法)

  • 使用1或2可以解决您的问题,但最好同时使用2或1


    有关此问题的更多信息,请阅读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);
    }