Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/259.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# 如何让异步代码等待所有任务完成?_C#_Asynchronous_.net 4.5 - Fatal编程技术网

C# 如何让异步代码等待所有任务完成?

C# 如何让异步代码等待所有任务完成?,c#,asynchronous,.net-4.5,C#,Asynchronous,.net 4.5,当我运行下面的代码时,在从HttpClient.GetAsync()调用返回结果之前,会出现消息“按Enter键继续…”。事件的实际顺序:调用GetAsync(),出现“按Enter…”消息,然后将结果逐个输出到控制台窗口。如何等到所有的GetAsync()调用完成后再显示“按Enter…”消息 类程序 { 静态HttpClient=新HttpClient(); 静态void Main(字符串[]参数) { RunAsync().Wait(); Console.WriteLine(“\n\n\n

当我运行下面的代码时,在从
HttpClient.GetAsync()
调用返回结果之前,会出现消息
“按Enter键继续…”
。事件的实际顺序:调用
GetAsync()
,出现“
按Enter…
”消息,然后将结果逐个输出到控制台窗口。如何等到所有的
GetAsync()
调用完成后再显示“
按Enter…
”消息

类程序
{
静态HttpClient=新HttpClient();
静态void Main(字符串[]参数)
{
RunAsync().Wait();
Console.WriteLine(“\n\n\n\n按Enter继续…”);
Console.ReadLine();
}
静态异步任务RunAsync()
{
列表URL=新列表()
{
"http://www.domain1.com",
"http://www.domain2.com",
"http://www.domain3.com",
"http://www.domain4.com"
};
foreach(url中的变量url)
{
下载页面异步(url);
}
}
静态异步任务下载页面异步(字符串url)
{
Console.WriteLine(“起始:+url”);
HttpResponseMessage response=wait client.GetAsync(url);
if(响应。IsSuccessStatusCode)
{
//在这里做事
}
Console.WriteLine(“完成:+url”);
返回response.Content.ToString();
}
}

由于
DownloadPageAsync
返回一个任务,您可以列出所有任务并等待它们:

Task.WhenAll(urls.Select(url => DownloadPageAsync(url)))
或简化:

Task.WhenAll(urls.Select(DownloadPageAsync))

由于
DownloadPageAsync
返回一个任务,您可以列出所有任务并等待它们:

Task.WhenAll(urls.Select(url => DownloadPageAsync(url)))
或简化:

Task.WhenAll(urls.Select(DownloadPageAsync))

我认为问题在于,您没有在
RunAsync()
方法中等待
DownloadPageAsync
方法。如果您将
RunAsync()
方法更新为下面的代码,那么我相信它会像您预期的那样工作:

static async Task RunAsync()
{
    List<string> urls = new List<string>()
    {
      "http://www.domain1.com",
      "http://www.domain2.com",
      "http://www.domain3.com",
      "http://www.domain4.com"
    };

    foreach (var url in urls)
    {
        // added await here
        await DownloadPageAsync(url);
    }
}
静态异步任务RunAsync()
{
列表URL=新列表()
{
"http://www.domain1.com",
"http://www.domain2.com",
"http://www.domain3.com",
"http://www.domain4.com"
};
foreach(url中的变量url)
{
//在这里添加等待
等待下载页面异步(url);
}
}

我认为问题在于您没有在
RunAsync()
方法中等待
DownloadPageAsync
方法。如果您将
RunAsync()
方法更新为下面的代码,那么我相信它会像您预期的那样工作:

static async Task RunAsync()
{
    List<string> urls = new List<string>()
    {
      "http://www.domain1.com",
      "http://www.domain2.com",
      "http://www.domain3.com",
      "http://www.domain4.com"
    };

    foreach (var url in urls)
    {
        // added await here
        await DownloadPageAsync(url);
    }
}
静态异步任务RunAsync()
{
列表URL=新列表()
{
"http://www.domain1.com",
"http://www.domain2.com",
"http://www.domain3.com",
"http://www.domain4.com"
};
foreach(url中的变量url)
{
//在这里添加等待
等待下载页面异步(url);
}
}

您需要为每个调用创建不同的任务,在您的示例中,您正在运行代码,而不是等待调用。当您调用WhenAll时,这只会为所有人创建一个任务。假设您使用下面的代码,并在每个MakeYouCall方法中在列表中插入一项。该列表将是您需要锁定的共享资源。当生成WhenAll时,如果不等待结果(调用wait()),则集合可能会被部分填充

var register1 = new Action(() => MakeYourCall1());
var register2 = new Action(() => MakeYourCall2());
var register3 = new Action(() => MakeYourCall3());
然后

var t1 = Task.Factory.StartNew(register1);
var t2 = Task.Factory.StartNew(register2);
var t3 = Task.Factory.StartNew(register3);
之后,您可以调用WhenAll返回任务,然后等待它

Task.WhenAll(t1, t2, t3).Wait();

您需要为每个调用创建不同的任务,在您的示例中,您正在运行代码,而不是等待调用。当您调用WhenAll时,这只会为所有人创建一个任务。假设您使用下面的代码,并在每个MakeYouCall方法中在列表中插入一项。该列表将是您需要锁定的共享资源。当生成WhenAll时,如果不等待结果(调用wait()),则集合可能会被部分填充

var register1 = new Action(() => MakeYourCall1());
var register2 = new Action(() => MakeYourCall2());
var register3 = new Action(() => MakeYourCall3());
然后

var t1 = Task.Factory.StartNew(register1);
var t2 = Task.Factory.StartNew(register2);
var t3 = Task.Factory.StartNew(register3);
之后,您可以调用WhenAll返回任务,然后等待它

Task.WhenAll(t1, t2, t3).Wait();

@patrik hofman的答案是一个很好的答案(投票率上升),不过,请看我的评论

如果您希望请求按顺序进行。。。 将
wait
添加到
DownloadPageAsync


您在
RunAsync
中使用了
async
,但没有
wait
s。因此,尽管它返回一个任务,但它并不等待
DownloadPageAsync
调用完成。这意味着该方法只返回一个立即完成的“空”任务。所以你的
.Wait()
什么也不等。

帕特里克·霍夫曼的答案很好(得票较高),不过,请看我的评论

如果您希望请求按顺序进行。。。 将
wait
添加到
DownloadPageAsync


您在
RunAsync
中使用了
async
,但没有
wait
s。因此,尽管它返回一个任务,但它并不等待
DownloadPageAsync
调用完成。这意味着该方法只返回一个立即完成的“空”任务。所以你的
.Wait()
什么也不等。

什么机制可以让你把它简化成
任务。什么时候(URL.Select(DownloadPageAsync))
?这是我第一次遇到这种格式。
Select
调用
Func
,而
DownloadPageAsync
恰好就是这种格式。请确保从
RunAsync
中删除
async
关键字,并返回
任务。whalll(…)
还请注意,这对于少量URL是可以的。如果你计划在100或1000年(如爬行器/爬虫)使用,那么你需要一种更复杂的方法来限制并发。我考虑的更多的是使用
MaxConcurrency
设置的
Parallel.ForEach
或自定义
TaskScheduler
。可能使用
BlockingCollection
作为输入队列和
getconsumineGenumerable
。比如什么机制允许