英文:
Why can't I get output from Parallel.ForEach in the code below?
问题
public static class Program
{
private static void Main(string[] args)
{
List<string> urls = new List<string> {
"https://www.microsoft.com",
"https://www.google.com",
"https://www.amazon.com"
};
List<string> Results = new List<string>();
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " 1");
Task.Run(() =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " 2");
HttpClient client = new HttpClient();
var p = Parallel.ForEach(urls, (url) =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " 3");
Console.WriteLine(url);
var content = client.GetStringAsync(url).Result;
Results.Add(url + " " + content.Length);
Console.WriteLine(url + " " + content.Length);
});
});
Console.WriteLine("Main program");
}
}
当运行这段代码时,我得到以下输出。
1 1
Main Program
为什么标记为2或3的地方没有输出?
所以在Task.Run()
和Parallel.ForEach()
中没有Console.WriteLine
的输出。
我想要打印所有线程的ID。
英文:
public static class Program
{
private static void Main(string[] args)
{
List<string> urls = new List<string> {
"https://www.microsoft.com",
"https://www.google.com",
"https://www.amazon.com"
};
List<string> Results = new List<string>();
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " 1");
Task.Run(() =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " 2");
HttpClient client = new HttpClient();
var p = Parallel.ForEach<string>(urls, (url) =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " 3");
Console.WriteLine(url);
var content = client.GetStringAsync(url).Result;
Results.Add(url + " " + content.Length);
Console.WriteLine(url + " " + content.Length);
});
});
Console.WriteLine("Main program");
}
}
When I run the code, I get an output like the one below.
1 1
Main Program
Why is there no output from the places I marked as 2 or 3?
So there is no output from Console.WriteLine
in Task.Run()
and Parallel.ForEach()
.
I want to print all thread ids.
答案1
得分: 1
以下是翻译好的部分:
// 原始代码
private static async Task Main(string[] args)
{
List<string> urls = new List<string> {
"https://www.microsoft.com",
"https://www.google.com",
"https://www.amazon.com"
};
List<string> Results = new List<string>();
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " 1");
await Task.Run(async () =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " 2");
HttpClient client = new HttpClient();
await Parallel.ForEachAsync<string>(urls, async (url, token) =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " 3");
Console.WriteLine(url);
var content = await client.GetStringAsync(url);
Results.Add(url + " " + content.Length);
Console.WriteLine(url + " " + content.Length);
});
});
Console.WriteLine("Main program");
}
// 建议后的代码
private static async Task Main(string[] args)
{
List<string> urls = new List<string> {
"https://www.microsoft.com",
"https://www.google.com",
"https://www.amazon.com"
};
List<string> Results = new List<string>();
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " 1");
HttpClient client = new HttpClient();
await Parallel.ForEachAsync<string>(urls, async (url, token) =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " 2");
Console.WriteLine(url);
var content = await client.GetStringAsync(url);
Results.Add(url + " " + content.Length);
Console.WriteLine(url + " " + content.Length);
});
Console.WriteLine("Main program");
}
请注意,我已经根据您的要求将代码翻译成中文,不包括代码部分。
英文:
Signature of Main
function can be updated to return async Task
instead of void
and use await
on Task.Run()
as shown below. In the updated code, the Parallel.ForEach
was updated as well to use the new Parallel.ForEachAsync()
to utilize async/await
magic
private static async Task Main(string[] args)
{
List<string> urls = new List<string> {
"https://www.microsoft.com",
"https://www.google.com",
"https://www.amazon.com"
};
List<string> Results = new List<string>();
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " 1");
await Task.Run(async () =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " 2");
HttpClient client = new HttpClient();
await Parallel.ForEachAsync<string>(urls, async (url, token) =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " 3");
Console.WriteLine(url);
var content = await client.GetStringAsync(url);
Results.Add(url + " " + content.Length);
Console.WriteLine(url + " " + content.Length);
});
});
Console.WriteLine("Main program");
}
Recommendation would be to remove Task.Run
altogether unless it is required for some other reason in code
private static async Task Main(string[] args)
{
List<string> urls = new List<string> {
"https://www.microsoft.com",
"https://www.google.com",
"https://www.amazon.com"
};
List<string> Results = new List<string>();
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " 1");
HttpClient client = new HttpClient();
await Parallel.ForEachAsync<string>(urls, async (url, token) =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " 2");
Console.WriteLine(url);
var content = await client.GetStringAsync(url);
Results.Add(url + " " + content.Length);
Console.WriteLine(url + " " + content.Length);
});
Console.WriteLine("Main program");
}
答案2
得分: 0
Task.Run
方法返回一个代表异步操作完成的 Task
对象。您必须等待操作完成,否则主线程将终止,然后在中止所有后台线程后,进程也将很快终止。等待任务完成的最简单方法是调用 Wait
方法:
Task.Run(() =>
{
//...
}).Wait();
英文:
The Task.Run
method returns a Task
object, that represents the completion of the asynchronous operation. You have to wait for the operation to complete, otherwise the main thread will terminate, and shortly after the process will terminate too after aborting all background threads. The simplest way to wait the task to complete is by calling the Wait
method:
Task.Run(() =>
{
//...
}).Wait();
答案3
得分: 0
当你调用Task.Run
时,你告诉线程在任务空闲时可以做其他事情。所以你的Task
不会被Main Thread
等待。就像下面的代码一样:
Task.Run(() => { /*任务工作*/ });
为了等待任务完成以恢复代码流程,只需在任务完成其工作时加上*await
关键字来与线程同步。Thread
将等待队列中的每个使用await*检查的任务完成后才终止。
await Task.Run(() => { /*任务工作*/ });
此外,你需要更新你的Main
方法签名,以允许异步调用:
static async Task Main()
英文:
When you call Task.Run
you say to thread that it could do other thing when the task is idle. So your Task
will not be waited by the Main Thread
. Like in the code bellow:
Task.Run(() => { /*task-job*/});
In order to wait the Task be completed to resume your code flow, just put await
keyword to synchronize the Task with Thread when its job is done. The Thread
will wait till every Task
checked with await be finished in the queue to die.
await Task.Run(() => { /*task-job*/});
Also, you have to update your Main method signature, to allow async calls:
static async Task Main()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论