首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Task.WaitAll的阻塞等待

Task.WaitAll的阻塞等待
EN

Stack Overflow用户
提问于 2022-11-23 11:40:11
回答 1查看 100关注 0票数 3

实际上,我正在学习async/wait,并试图亲自了解await Task.WhenAllTask.WaitAll在CPU绑定操作中的好处。当每个人写到Task.WaitAll提供阻塞等待时,await Task.WhenAll提供非阻塞等待。

我创建了一个示例,在这个示例中,我希望用一个Task.WaitAll替换await Task.WhenAll,并亲眼看到还有一个自由线程。但是我看到,即使是Task.WaitAll也不会阻塞线程。我的问题与此有关。在Task.WaitAll的例子中,我看到在执行Task.WaitAll的同一个线程中,正在执行另一个任务。但是,如果我包括Thread.Sleepwhile (true)而不是Task.WaitAll,那么程序的行为就会像预期的那样。

我认为Main方法将创建任务MyTask (-1个工作线程),它将创建16个任务条件为B1-B16 (-15个工作线程,因为一个工作线程忙于任务MyTask,总共有16个工作线程),任务MyTask将有一个阻塞等待Task.WaitAll,我将看到16个正在运行的任务中的15个。但是我看到所有16个正在运行的任务,其中一个运行在任务MyTask运行的同一个线程上。

问题.为什么Task.WaitAll不阻止在本例中执行它的线程,而不像Thread.Sleepwhile (true)?有人能一步一步地解释线程4中的两个任务的代码在使用Task.WaitAll时是如何工作的吗?为什么任务MyTask运行的线程也被任务条件B16使用?

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {        
        static void Main(string[] args)
        {
            Console.WriteLine($"Main                Thread: {Thread.CurrentThread.ManagedThreadId}");

            int ProcessorCount = Environment.ProcessorCount;
            ThreadPool.SetMaxThreads(ProcessorCount, ProcessorCount);
            int Counter = 0;
            List<Task> MyListForTask = new List<Task>();

            void MyMethod()
            {
                lock (MyListForTask)
                {
                    Counter++;
                    Console.WriteLine($"Counter: {Counter}        Thread: {Thread.CurrentThread.ManagedThreadId}");
                }
                
                //Thread.Sleep(int.MaxValue);
                while (true) { };
            }

            Task MyTask = Task.Run(() =>
            {
                Console.WriteLine($"MyTask            Thread: {Thread.CurrentThread.ManagedThreadId}\n");

                for (int i = 0; i < ProcessorCount; i++)
                {
                    MyListForTask.Add(Task.Run(MyMethod));
                }

                //Thread.Sleep(int.MaxValue);
                //while (true) { };
                Task.WaitAll(MyListForTask.ToArray());                
            });

            MyTask.Wait();
        }
    }
}

EN

回答 1

Stack Overflow用户

发布于 2022-11-23 11:50:05

multithreading / asynchronous编程的全部目的是尽可能有效地使用您的CPU资源,而您不关心操作的顺序。

不能保证任务是按顺序开始的,它们也将按顺序完成。

顾名思义,Thread.Sleep会主动阻塞CPU线程(不会接收另一个任务),并在执行任务之前等待所需条件(x时间传递),然后再选择另一个任务。简而言之,Thread.Sleep可以防止asynchronous行为的发生。

在这里,您可以更直观地看到每个人将做什么。输出将不是连续的1-100,而是随机的.

由于任务仍在启动/正在执行,WhenAll甚至首先打印DoSomethingElse。

WaitAll将在打印DoSomethingElse之前等待这些任务,尽管这会减慢执行速度。

如前所述,睡眠只会增加时间。您可以将线程放置在异步或“同步”方法中,但它所做的唯一事情就是将执行时间添加到程序中。唯一的区别是,在异步中,其他可用线程将占用空闲时间(如果可用的话)。

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Fiddle

{
    public class Program
    {
    public static void Main(string[] args)
    {

        var ladieDo = new DoSomething();
        ladieDo.RunAsyncAndDontAwaitCompletion();

        Console.ReadLine();
        Console.Clear();

        ladieDo.RunAsyncAndAwaitCompletionOfAll();

        Console.ReadLine();
    }


    public class DoSomething
    {
        public void RunAsyncAndDontAwaitCompletion()
        {
            var proces = Process.GetCurrentProcess();
            Console.WriteLine("Threads:" + proces.Threads);
            var ints = Enumerable.Range(1, 100).ToList();

            // Will report back when its done, but wont wait for everything
            Task.WhenAll(ints.Select(a => Task.Run(() => Console.WriteLine(a))));

            // This line will be executed as soon as a Thread opens up, regardless of whether the above tasks have been completed
            Console.WriteLine("DoSomethingElse");
            Console.ReadLine();
        }

        public void RunAsyncAndAwaitCompletionOfAll()
        {
            var proces = Process.GetCurrentProcess();
            Console.WriteLine("Threads:" + proces.Threads);
            var ints = Enumerable.Range(1, 100).ToList();

            // wait untill all these tasks are done
            Task.WaitAll(ints.Select(a => Task.Run(() => Console.WriteLine(a))).ToArray());

            // only once above tasks are done (regardless of order), write this
            Console.WriteLine("DoSomethingElse");
        }

        public void EachTaskWillRunSynchronously()
        {
            var proces = Process.GetCurrentProcess();
            Console.WriteLine("Threads:" + proces.Threads);
            var ints = Enumerable.Range(1, 100).ToList();

            foreach (int i in ints)
            {
                Console.WriteLine(i);
                
                // The below line will just add more time in between each output
                //Thread.Sleep(10);
            }

            Console.WriteLine("DoSomethingElse");
        }
    }
}

}

输出:

代码语言:javascript
复制
DoSomethingElse
1
2
3
4
6
7
8
9
10
11
12
13
14
5
....
    89
90
91
92
93
94
88
84
97
98
96
100
99
95
DoSomethingElse
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74546215

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档