为什么我无法从下面的代码中获得Parallel.ForEach的输出?

huangapple go评论67阅读模式
英文:

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&lt;string&gt; urls = new List&lt;string&gt; {
            &quot;https://www.microsoft.com&quot;,
            &quot;https://www.google.com&quot;,
            &quot;https://www.amazon.com&quot;
        };

        List&lt;string&gt; Results = new List&lt;string&gt;();
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId + &quot; 1&quot;);

        Task.Run(() =&gt;
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId + &quot; 2&quot;);
            HttpClient client = new HttpClient();
            var p = Parallel.ForEach&lt;string&gt;(urls, (url) =&gt;
            {
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId + &quot; 3&quot;);
                Console.WriteLine(url);
                var content = client.GetStringAsync(url).Result;
                Results.Add(url + &quot; &quot; + content.Length);
                Console.WriteLine(url + &quot; &quot; + content.Length);
            });
        });

        Console.WriteLine(&quot;Main program&quot;);
    }
}

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&lt;string&gt; urls = new List&lt;string&gt; {
        &quot;https://www.microsoft.com&quot;,
        &quot;https://www.google.com&quot;,
        &quot;https://www.amazon.com&quot;
    };

    List&lt;string&gt; Results = new List&lt;string&gt;();
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId + &quot; 1&quot;);

    await Task.Run(async () =&gt;
    {
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId + &quot; 2&quot;);
        HttpClient client = new HttpClient();
        await Parallel.ForEachAsync&lt;string&gt;(urls, async (url, token) =&gt;
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId + &quot; 3&quot;);
            Console.WriteLine(url);
            var content = await client.GetStringAsync(url);
            Results.Add(url + &quot; &quot; + content.Length);
            Console.WriteLine(url + &quot; &quot; + content.Length);
        });
    });

    Console.WriteLine(&quot;Main program&quot;);
}

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&lt;string&gt; urls = new List&lt;string&gt; {
        &quot;https://www.microsoft.com&quot;,
        &quot;https://www.google.com&quot;,
        &quot;https://www.amazon.com&quot;
    };

    List&lt;string&gt; Results = new List&lt;string&gt;();
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId + &quot; 1&quot;);
    HttpClient client = new HttpClient();
    await Parallel.ForEachAsync&lt;string&gt;(urls, async (url, token) =&gt;
    {
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId + &quot; 2&quot;);
        Console.WriteLine(url);
        var content = await client.GetStringAsync(url);
        Results.Add(url + &quot; &quot; + content.Length);
        Console.WriteLine(url + &quot; &quot; + content.Length);
    });

    Console.WriteLine(&quot;Main program&quot;);
}

答案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(() =&gt;
{
    //...
}).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(() =&gt; { /*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 Taskchecked with await be finished in the queue to die.

await Task.Run(() =&gt; { /*task-job*/});

Also, you have to update your Main method signature, to allow async calls:

static async Task Main()

huangapple
  • 本文由 发表于 2023年6月22日 03:35:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/76526583.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定