【发布时间】:2018-05-24 22:00:41
【问题描述】:
尽管async 和await 已经出现了一段时间,而且作为一个长期的C# 开发人员,我仍然很难真正理解它们是如何工作的以及何时使用它们。所以我正在写一些测试代码!
我正在尝试异步从主线程调用任务A,然后调用任务 B 当任务 A 完成时,然后调用任务 C。
在伪代码中,这类似于:
RunAsync(TaskA())
.Then(TaskB())
.Then(TaskC());
我已经编写了以下示例,但它的行为与我预期的不同。相反,或者先运行 A,然后运行 B,然后运行 C,它运行 A,然后运行 B 和 C 并行运行。
C# sn-p 如下(详情如下):
Task
.Run(async () => await LongTaskAsync("A"))
.ContinueWith(async (taskA) => await LongTaskAsync("B"))
.ContinueWith(async (taskB) => await LongTaskAsync("C"));
我打印出线程 ID,并且我有:
- 主线程 ID 1
- 任务 A 的 ID 2
- 任务 B 和 C 的 ID 4
- 没有 ID 3(或我忽略的某个地方)
代码如下:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace AsyncTests
{
class Program
{
private static DateTime _start;
static void Main(string[] args)
{
_start = DateTime.Now;
Log("======= Main thread starts ======");
Log($"Main thread ID : {Thread.CurrentThread.ManagedThreadId}");
// Start a stack of aynchronous calls
Task
.Run(async () => await LongTaskAsync("A"))
.ContinueWith(async (taskA) => await LongTaskAsync("B"))
.ContinueWith(async (taskB) => await LongTaskAsync("C"));
Log("====== Main thread returns ======");
Console.ReadKey();
}
static async Task LongTaskAsync(string name)
{
Log($"Long async task {name} starts");
Log($"{name} thread ID : {Thread.CurrentThread.ManagedThreadId}");
for(var i = 1 ; i <= 5 ; i++)
{
Log($"Task {name} says {i}");
await Task.Delay(1000);
}
Log($"Long async task {name} returns");
}
static void Log(string text)
{
var elpased = (int)(DateTime.Now - _start).TotalMilliseconds;
Console.WriteLine($"[+{elpased.ToString().PadLeft(4,'0')}] {text}");
}
}
}
还有控制台输出:
[+0003] ======= Main thread starts ======
[+0009] Main thread ID : 1
[+0016] ====== Main thread returns ======
[+0022] Long async task A starts
[+0024] A thread ID : 3
[+0024] Task A says 1
[+1028] Task A says 2
[+2029] Task A says 3
[+3030] Task A says 4
[+4031] Task A says 5
[+5032] Long async task A returns
[+5034] Long async task B starts
[+5034] B thread ID : 4
[+5034] Task B says 1
[+5035] Long async task C starts
[+5036] C thread ID : 4
[+5036] Task C says 1
[+6036] Task C says 2
[+6036] Task B says 2
[+7037] Task C says 3
[+7037] Task B says 3
[+8038] Task B says 4
[+8038] Task C says 4
[+9039] Task C says 5
[+9039] Task B says 5
[+10040] Long async task C returns
[+10040] Long async task B returns
【问题讨论】:
-
为什么你要制作所有的 lambdas
async,而他们什么都不做,但反对在一种可以实际使用它的方法中使用async? -
正如我在介绍文本中所说的,我对异步编程无论是 C# 还是任何语言都感到不舒服。因此,对这些关键字的误解使用是很有可能的。关于重复,我不认为这个问题是重复的,因为我的细节是链接几个 ContinueWith,而其他涉及一次调用。基本上,我的问题是“是否应该将
ContinueWith视为 JS/TS 中 Primises 上的 Then() 的 C# 等价物”。 -
您需要将解决方案应用三次而不是一次,这一事实并没有使它成为一个根本不同的问题。如果您正在做需要修复三遍的事情,那么将解决方案应用三遍。
标签: c# async-await task