实际上,我正在学习async/wait,并试图亲自了解await Task.WhenAll与Task.WaitAll在CPU绑定操作中的好处。当每个人写到Task.WaitAll提供阻塞等待时,await Task.WhenAll提供非阻塞等待。
我创建了一个示例,在这个示例中,我希望用一个Task.WaitAll替换await Task.WhenAll,并亲眼看到还有一个自由线程。但是我看到,即使是Task.WaitAll也不会阻塞线程。我的问题与此有关。在Task.WaitAll的例子中,我看到在执行Task.WaitAll的同一个线程中,正在执行另一个任务。但是,如果我包括Thread.Sleep或while (true)而不是Task.WaitAll,那么程序的行为就会像预期的那样。
我认为Main方法将创建任务MyTask (-1个工作线程),它将创建16个任务条件为B1-B16 (-15个工作线程,因为一个工作线程忙于任务MyTask,总共有16个工作线程),任务MyTask将有一个阻塞等待Task.WaitAll,我将看到16个正在运行的任务中的15个。但是我看到所有16个正在运行的任务,其中一个运行在任务MyTask运行的同一个线程上。
问题.为什么Task.WaitAll不阻止在本例中执行它的线程,而不像Thread.Sleep或while (true)?有人能一步一步地解释线程4中的两个任务的代码在使用Task.WaitAll时是如何工作的吗?为什么任务MyTask运行的线程也被任务条件B16使用?
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();
}
}
}




发布于 2022-11-23 11:50:05
multithreading / asynchronous编程的全部目的是尽可能有效地使用您的CPU资源,而您不关心操作的顺序。
不能保证任务是按顺序开始的,它们也将按顺序完成。
顾名思义,Thread.Sleep会主动阻塞CPU线程(不会接收另一个任务),并在执行任务之前等待所需条件(x时间传递),然后再选择另一个任务。简而言之,Thread.Sleep可以防止asynchronous行为的发生。
在这里,您可以更直观地看到每个人将做什么。输出将不是连续的1-100,而是随机的.
由于任务仍在启动/正在执行,WhenAll甚至首先打印DoSomethingElse。
WaitAll将在打印DoSomethingElse之前等待这些任务,尽管这会减慢执行速度。
如前所述,睡眠只会增加时间。您可以将线程放置在异步或“同步”方法中,但它所做的唯一事情就是将执行时间添加到程序中。唯一的区别是,在异步中,其他可用线程将占用空闲时间(如果可用的话)。
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");
}
}
}}
输出:
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
DoSomethingElsehttps://stackoverflow.com/questions/74546215
复制相似问题