原文地址:devblogs.microsoft.com/oldnewthing…
原文作者:devblogs.microsoft.com/oldnewthing…
发布时间:2019年5月1日
上一次,我们了解到一个名为Async-Async的功能,它通过假装异步操作在实际开始之前就已经开始了,从而使异步操作变得更加异步。Async-Async的引入旨在对客户端和服务器都是透明的,前提是他们一开始就遵守了规则。当然,如果你没有遵守规则,那么你可能会发现一些副作用。
从客户端来看,这意味着在操作完成之前,你不能突变异步操作的参数。这从一开始就不被允许,但人们有时会侥幸逃脱,因为他们 "知道 "在初始方法返回异步操作之前,某些参数已经被消耗掉了。
// Create three widgets in parallel.
var options = new WidgetOptions();
// Create a blue widget.
options.Color = Colors.Blue;
var task1 = Widget.CreateAsync(options);
// Create another blue widget.
var task2 = Widget.CreateAsync(options);
// Create a red widget.
options.Color = Colors.Red; // Code is wrong.
var task3 = Widget.CreateAsync(options); // Code is wrong.
// Wait for all the widgets to be created.
await Task.WhenAll(task1, task2, task3);
// Get the widgets.
var widget1 = task1.Result;
var widget2 = task2.Result;
var widget3 = task3.Result;
这段代码 "知道 "Widget.CreateAsync方法在返回一个IAsyncOperation之前会查看options.Color。因此,它 "知道 "在 Widget.CreateAsync 返回后对选项的任何更改都不会对正在创建的小组件产生任何影响,所以它继续并重新配置选项对象,以便它可以用于第三个小组件。
当启用Async-Async时,该代码不起作用。对Widget.CreateAsync的调用会立即返回假的AsyncOperations,而对Widget.CreateAsync的真正调用仍在进行中。正如我们前面所看到的,真正调用Widget.CreateAsync的结果将与假的IAsyncOperation相连,这样你就能得到你想要的结果,但是为了提高性能,改变了时间。如果上面的代码设法在Widget.CreateAsync的前两个真实调用之一读取选项之前将options.Color改为红色,那么前两个widget中的一个或两个最终将变成红色而不是蓝色。
这基本上是违反了编程的基本规则之一。你不能在函数调用过程中改变参数。只是对于异步操作来说,"进行中 "一直延伸到异步操作的完成。
启动多个异步操作是可以的。只要确保它们不相互干扰即可。
// Create three widgets in parallel.
var options = new WidgetOptions();
// Create a blue widget.
options.Color = Colors.Blue;
var task1 = Widget.CreateAsync(options);
// Create another blue widget.
var task2 = Widget.CreateAsync(options);
// Create a red widget.
options = new WidgetOptions(); // important
options.Color = Colors.Red;
var task3 = Widget.CreateAsync(options);
// Wait for all the widgets to be created.
await Task.WhenAll(task1, task2, task3);
// Get the widgets.
var widget1 = task1.Result;
var widget2 = task2.Result;
var widget3 = task3.Result;
这次,我们为Widget.CreateAsync的最后一次调用创建一个新的WidgetOptions对象。这样,每次调用Widget.CreateAsync都会得到一个在调用期间稳定的选项对象。在多个调用之间共享选项对象是可以的(就像我们对前两个蓝色widgets所做的那样),但不要在还有异步操作在使用它们的时候改变它们。
当然,一旦操作完成,你可以对选项做任何你想做的事情,因为操作不再使用它们了。
// Create three widgets in series.
var options = new WidgetOptions();
// Create a blue widget.
options.Color = Colors.Blue;
var widget1 = await Widget.CreateAsync(options);
// Create another blue widget.
var widget2 = await Widget.CreateAsync(options);
// Create a red widget.
options.Color = Colors.Red;
var widget3 = await Widget.CreateAsync(options);
在本例中,我们以系列的方式创建了widget.CreateAsync(options); //创建红色的widget。我们在等待操作结果后修改了选项,所以我们知道操作已经完成,修改选项进行新的调用是安全的。
下一次,我们来看看Async-Async的另一个后果。