有人能解释一下,为什么在AfterAll触发后此代码只会陷入死胡同吗?
主要代码:
class AsyncTests
{
public async void Start()
{
Console.WriteLine($"Thread:{Thread.CurrentThread.ManagedThreadId} - starting whole process, calling await DoWork1()");
await Task.WhenAll(DoWork1(), DoWork2());
Console.WriteLine($"Thread:{Thread.CurrentThread.ManagedThreadId} - finished awaiting DoWork1 and DoWork2");
}
public async Task DoWork1()
{
Console.WriteLine($"Thread:{Thread.CurrentThread.ManagedThreadId} - starting DoWork1");
await DoNothing();
Console.WriteLine($"Thread:{Thread.CurrentThread.ManagedThreadId} - finished DoWork1");
}
public async Task DoWork2()
{
Console.WriteLine($"Thread:{Thread.CurrentThread.ManagedThreadId} - starting DoWork2");
await DoNothing();
Console.WriteLine($"Thread:{Thread.CurrentThread.ManagedThreadId} - finished DoWork2");
}
public Task DoNothing() { return new Task(() => { /* do nothing */ }); }
}
程序控制代码:
static void Main(string[] args)
{
var x = new AsyncTests();
Console.WriteLine($"Thread:{Thread.CurrentThread.ManagedThreadId} - Main ... calling Start()");
Task.Run(() => x.Start());
Console.WriteLine($"Thread:{Thread.CurrentThread.ManagedThreadId} - Main ... start is running");
Console.ReadKey();
}
输出:
Thread:1 - Main ... calling Start()
Thread:1 - Main ... start is running
Thread:4 - starting whole process, calling await DoWork1()
Thread:4 - starting DoWork1
Thread:4 - starting DoWork2
更新
为了更清楚一点,让我们对其进行更改,以便DoNothing实际调用Thread.Sleep(2000),我的目标是同时运行两个线程睡眠,并希望使用async / await模式来实现这一点。
如果我将“ DoNothing”更改为执行睡眠的异步任务,那么我被告知我需要await
操作符。这意味着我需要编写另一个async
方法来等待。那么从运营商的角度来看,结束通话链的最佳方法是什么?
有人可以举例说明如何实现上述目标吗?
答案 0 :(得分:4)
您永远不会在NoNothing中开始您的任务。
分隔任务创建和执行
Task类还提供了初始化任务但不安排执行任务的构造函数。出于性能原因,Task.Run或TaskFactory.StartNew方法是创建和调度计算任务的首选机制,但是对于必须将创建和调度分开的情况,可以使用构造函数,然后调用Task.Start方法进行调度。该任务以便以后执行。
答案 1 :(得分:0)
让该语言为您完成任务,而不是创建要返回的任务。
public async Task DoNothing() { }
以上内容实际上不执行任何操作,并且会返回处于完成状态的Task
,可以等待。
您目前正在执行的方式是创建任务,但它从未启动或设置为已完成,因此等待它会永远锁定程序。
答案 2 :(得分:0)
仅是为了补充已经给出的答案和注释,我想展示一个代码示例,其工作方式与测试中的预期目的相同。它显示信息的执行流+,特定时间执行的托管线程ID。
主要代码:
class AsyncTests
{
public async Task StartAsync()
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} - Thread:{Thread.CurrentThread.ManagedThreadId} - starting whole process, calling await DoWork1Async()");
await Task.WhenAll(DoWork1Async(), DoWork2Async());
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} - Thread:{Thread.CurrentThread.ManagedThreadId} - finished awaiting DoWork1Async and DoWork2Async");
}
public async Task DoWork1Async()
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} - Thread:{Thread.CurrentThread.ManagedThreadId} - starting DoWork1Async");
await Sleep();
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} - Thread:{Thread.CurrentThread.ManagedThreadId} - finished DoWork1Async");
}
public async Task DoWork2Async()
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} - Thread:{Thread.CurrentThread.ManagedThreadId} - starting DoWork2Async");
await Sleep();
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} - Thread:{Thread.CurrentThread.ManagedThreadId} - finished DoWork2Async");
}
public async Task Sleep()
{
await Task.Delay(2000);
}
}
调用代码(请注意,要使其异步运行,我必须省去await
运算符,该运算符在consider applying the 'await' operator
方法调用中引发警告StartAsync()
。
static void Main(string[] args)
{
var x = new AsyncTests();
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} - {Thread.CurrentThread.ManagedThreadId} - Main ... calling Start()");
x.StartAsync();
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} - {Thread.CurrentThread.ManagedThreadId} - Main ... start is running");
Console.ReadKey();
}
最后,输出-如预期的那样,显示代码执行/控制返回到真正异步操作所需的位置。正如预期的那样,使用了两个不同的池线程来运行睡眠。
10:43:36.515 - 1 - Main ... calling Start()
10:43:36.546 - Thread:1 - starting whole process, calling await DoWork1Async()
10:43:36.547 - Thread:1 - starting DoWork1Async
10:43:36.561 - Thread:1 - starting DoWork2Async
10:43:36.562 - 1 - Main ... start is running
10:43:38.581 - Thread:4 - finished DoWork2Async
10:43:38.582 - Thread:5 - finished DoWork1Async
10:43:38.582 - Thread:5 - finished awaiting DoWork1Async and DoWork2Async