这系列教学文的目的是要探索具备非同步功能的框架在底层发生了什麽事, 甚至写一个简单的框架出来, 目前我们终於进展到阅读我们的第一个目标 .Net 。 之所以选择 .Net 作为开始, 一是因为我 C# 比较熟, 二是因为他们拥有很好的文件和索引, 三是因为他们的封装逻辑很棒(个人感受), 那我们就一起来看看吧。
https://docs.microsoft.com/zh-tw/dotnet/api/system.threading.tasks.task.whenall?view=net-5.0
怕大家不懂 C# , 这边说明一下, Task.WhenAll 的功能和 JS 的 Promise.all 差不多。
说白了就是停下来等待一堆非同步工作的执行。
要先包装出多个非同步工作, 接着把这些工作当参数传入 WhenAll, 最後 WhenAll 会回传执行结果。这个方法应该是 C# 使用端在实践非同步 programming 得常见做法了吧。
.Net reference source
https://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/Task.cs,5955
///
/// Creates a task that will complete when all of the supplied tasks have completed.
///
/// The tasks to wait on for completion.
/// A task that represents the completion of all of the supplied tasks.
///
///
/// If any of the supplied tasks completes in a faulted state, the returned task will also complete in a Faulted state,
/// where its exceptions will contain the aggregation of the set of unwrapped exceptions from each of the supplied tasks.
///
///
/// If none of the supplied tasks faulted but at least one of them was canceled, the returned task will end in the Canceled state.
///
///
/// If none of the tasks faulted and none of the tasks were canceled, the resulting task will end in the RanToCompletion state.
///
///
/// If the supplied array/enumerable contains no tasks, the returned task will immediately transition to a RanToCompletion
/// state before it's returned to the caller.
///
可以知道
我们要读的是这个 overload public static Task WhenAll(params Task[] tasks)
public static Task WhenAll(params Task[] tasks)
{
// Do some argument checking and make a defensive copy of the tasks array
if (tasks == null) throw new ArgumentNullException("tasks");
Contract.EndContractBlock();
int taskCount = tasks.Length;
if (taskCount == 0) return InternalWhenAll(tasks); // Small optimization in the case of an empty array.
Task[] tasksCopy = new Task[taskCount];
for (int i = 0; i < taskCount; i++)
{
Task task = tasks[i];
if (task == null) throw new ArgumentException(Environment.GetResourceString("Task_MultiTaskContinuation_NullTask"), "tasks");
tasksCopy[i] = task;
}
// 以上例外处理, 跳过。
// The rest can be delegated to InternalWhenAll()
return InternalWhenAll(tasksCopy);
}
可以发现, 其复制了一份传入参数, 丢入 InternalWhenAll(tasksCopy)
, 代其回传。
接着我们读一下 InternalWhenAll(tasksCopy)
private static Task InternalWhenAll(Task[] tasks)
{
Contract.Requires(tasks != null, "Expected a non-null tasks array");
return (tasks.Length == 0) ? // take shortcut if there are no tasks upon which to wait
Task.CompletedTask :
new WhenAllPromise(tasks);
}
发现他除了例外处理以外, 又往下丢一层, 进入 WhenAllPromise(tasks)
internal WhenAllPromise(Task[] tasks) : base()
{
Contract.Requires(tasks != null, "Expected a non-null task array");
Contract.Requires(tasks.Length > 0, "Expected a non-zero length task array");
if (AsyncCausalityTracer.LoggingOn)
AsyncCausalityTracer.TraceOperationCreation(CausalityTraceLevel.Required, this.Id, "Task.WhenAll", 0);
if (s_asyncDebuggingEnabled)
{
AddToActiveTasks(this);
}
m_tasks = tasks;
// 记下任务总数
m_count = tasks.Length;
foreach (var task in tasks)
{
// 当这个任务被判断为已经完成, 则走捷径
if (task.IsCompleted) this.Invoke(task); // short-circuit the completion action, if possible
else task.AddCompletionAction(this); // simple completion action
}
}
一般来说要看一下继承, 但 base()
是空的, 跳过。
跳过 log 相关, debug 相关, 我们可以发现两条核心方法, this.Invoke(task)
和 task.AddCompletionAction(this)
两条, 但从注解可以看出, 走Invoke
是 AddCompletionAction
的捷径, 我们先读Invoke
。 这里的 this 指的是等待所有任务完成的任务, 就是本 method 的调用者。
读 public void Invoke(Task completedTask)
https://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/Task.cs,6123
较长, 可以直接到 reference 看, 这里撷取语句
// atomic 的把 task 的数量减一, 如果减完是 0 表示任务全部完成
if (Interlocked.Decrement(refm_count) == 0)
{
// 设定回传结果, 略
}
我们整理一下 当 whenAll 开始运行, 会先取得传入的 task 总数, 接着依序对传入的 task 判断状态, 若是判断为 task 已完成时, 会把 task 总数减1, 当总数被减为 0 时, 会设定回传结果且回传。
Interlocked.Decrement 文件
https://docs.microsoft.com/zh-tw/dotnet/api/system.threading.interlocked.decrement?view=net-5.0
今天我们留下了两个疑问, 要交给明天的我解决。
明天见!
>>: [Day05] Tableau 轻松学 - Tableau 授权类型
实例变数 实例变数(instance variable)拥有储存资料成员的记忆体空间,不与其他物件共...
electronic mail 三要件 1. user agents(UA) 邮件使用者代理人,也叫...
上篇介绍了CSS Flex,这篇想来聊聊CSS grid到底是什麽东西 这里想先给大家一个观念: F...
Qualcomm has recently announced its upcoming 5G mo...
Use Case Spec 这边以之前的 use case 当作例子来撰写测试。 首先要能快速地建立...