什么';这是新C#异步特性的一个很好的非网络化示例?
微软刚刚宣布了这一计划。到目前为止,我看到的每个示例都是关于从HTTP异步下载内容的。当然还有其他重要的异步功能 假设我没有编写新的RSS客户端或Twitter应用程序。C#Async对我来说有什么有趣的地方什么';这是新C#异步特性的一个很好的非网络化示例?,c#,c#-5.0,async-await,C#,C# 5.0,Async Await,微软刚刚宣布了这一计划。到目前为止,我看到的每个示例都是关于从HTTP异步下载内容的。当然还有其他重要的异步功能 假设我没有编写新的RSS客户端或Twitter应用程序。C#Async对我来说有什么有趣的地方 编辑我有一个哈哈哈!看电视的时候。在过去,我曾在使用“观察者”线程的程序上工作。这些线程等待某些事情发生,就像等待文件更改一样。它们没有做任何工作,只是处于空闲状态,并在发生某些事情时通知主线程。在新模型中,这些线程可以用wait/async代码替换。Ooh,这听起来很有趣。我不是在玩CT
编辑我有一个哈哈哈!看电视的时候。在过去,我曾在使用“观察者”线程的程序上工作。这些线程等待某些事情发生,就像等待文件更改一样。它们没有做任何工作,只是处于空闲状态,并在发生某些事情时通知主线程。在新模型中,这些线程可以用wait/async代码替换。Ooh,这听起来很有趣。我不是在玩CTP,只是在看白皮书。在看过之后,我想我可以看到它是如何被证明是有用的 据我所知,async使编写异步调用更易于阅读和实现。同样,现在编写迭代器更容易(而不是手工编写功能)。这是阻塞进程的关键,因为在解除阻塞之前,无法完成任何有用的工作。如果你正在下载一个文件,你不能做任何有用的事情,直到你得到那个文件,让线程浪费掉。考虑一下你如何调用一个函数,你知道它会阻塞一个不确定的长度,并返回一些结果,然后处理它(例如,将结果存储在一个文件中)。你会怎么写?下面是一个简单的例子:
static object DoSomeBlockingOperation(object args)
{
// block for 5 minutes
Thread.Sleep(5 * 60 * 1000);
return args;
}
static void ProcessTheResult(object result)
{
Console.WriteLine(result);
}
static void CalculateAndProcess(object args)
{
// let's calculate! (synchronously)
object result = DoSomeBlockingOperation(args);
// let's process!
ProcessTheResult(result);
}
private async void doCalculation_Click(object sender, RoutedEventArgs e) {
doCalculation.IsEnabled = false;
await DoSomeBlockingOperationAsync(GetArgs());
doCalculation.IsEnabled = true;
}
好的,很好,我们已经实施了。但是等等,计算需要几分钟才能完成。如果我们想要一个交互式应用程序,并在计算过程中做其他事情(例如呈现UI),该怎么办?这是不好的,因为我们同步调用了函数,我们必须等待它完成有效地冻结应用程序,因为线程正在等待解除阻塞
回答,异步调用函数昂贵函数。这样我们就不必等待阻塞操作完成。但是我们怎么做呢?我们将异步调用该函数,并注册一个回调函数,以便在取消阻塞时调用,以便处理结果
static void CalculateAndProcessAsyncOld(object args)
{
// obtain a delegate to call asynchronously
Func<object, object> calculate = DoSomeBlockingOperation;
// define the callback when the call completes so we can process afterwards
AsyncCallback cb = ar =>
{
Func<object, object> calc = (Func<object, object>)ar.AsyncState;
object result = calc.EndInvoke(ar);
// let's process!
ProcessTheResult(result);
};
// let's calculate! (asynchronously)
calculate.BeginInvoke(args, cb, calculate);
}
如果您做过任何UI编程(无论是WinForms还是WPF)并试图在处理程序中调用昂贵的函数,您就会知道这很方便。使用后台工作线程对此没有多大帮助,因为后台线程将一直坐在那里等待,直到它可以工作
假设你有一种控制外部设备的方法,比如说一台打印机。您希望在发生故障后重新启动设备。当然,打印机启动并准备好运行需要一些时间。您可能必须说明重新启动没有帮助,然后再次尝试重新启动。你别无选择,只能等待。如果异步执行,则不会
static async void RestartPrinter()
{
Printer printer = GetPrinter();
do
{
printer.Restart();
printer = await printer.WaitUntilReadyAsync();
} while (printer.HasFailed);
}
想象一下在没有异步的情况下编写循环
我还有最后一个例子。想象一下,如果您必须在一个函数中执行多个阻塞操作,并且希望异步调用。你喜欢什么
static void DoOperationsAsyncOld()
{
Task op1 = new Task(DoOperation1Async);
op1.ContinueWith(t1 =>
{
Task op2 = new Task(DoOperation2Async);
op2.ContinueWith(t2 =>
{
Task op3 = new Task(DoOperation3Async);
op3.ContinueWith(t3 =>
{
DoQuickOperation();
}
op3.Start();
}
op2.Start();
}
op1.Start();
}
static async void DoOperationsAsyncNew()
{
await DoOperation1Async();
await DoOperation2Async();
await DoOperation3Async();
DoQuickOperation();
}
阅读,它实际上有很多实用的例子,比如写并行任务和其他
我迫不及待地想在CTP或.NET 5.0最终成功时开始使用它。今天我发现了另一个很好的使用案例:您可以等待用户交互 例如,如果一个窗体具有打开另一个窗体的按钮:
Form toolWindow;
async void button_Click(object sender, EventArgs e) {
if (toolWindow != null) {
toolWindow.Focus();
} else {
toolWindow = new Form();
toolWindow.Show();
await toolWindow.OnClosed();
toolWindow = null;
}
}
当然,这并不比
toolWindow.Closed += delegate { toolWindow = null; }
但我认为它很好地展示了等待
可以做什么。一旦事件处理程序中的代码非常重要,await
将使编程变得更加容易。设想用户必须单击一系列按钮:
async void ButtonSeries()
{
for (int i = 0; i < 10; i++) {
Button b = new Button();
b.Text = i.ToString();
this.Controls.Add(b);
await b.OnClick();
this.Controls.Remove(b);
}
}
不幸的是,似乎无法将GetAwaiter()
方法直接添加到EventHandler
(允许wait按钮。单击;
)中,因为这样该方法就不知道如何注册/取消注册该事件。
这有点像样板文件,但是AwaitableEvent类可以用于所有事件(不仅仅是UI)。只需稍加修改并添加一些泛型,就可以检索EventArgs:
MouseEventArgs e = await button.OnMouseDown();
我可以看到这对一些更复杂的UI手势(拖放、鼠标手势等)很有用,不过您必须添加取消当前手势的支持。CTP中有一些示例和演示不使用网络,甚至有些不做任何I/O 它确实适用于所有多线程/并行问题领域(已经存在)
Async和Await是构造所有并行代码的一种新的(更简单的)方法,无论是CPU绑定还是I/O绑定。最大的改进是在C#5之前必须使用APM(IAsyncResult)模型或事件模型(BackgroundWorker、WebClient)的领域。我认为这就是为什么这些例子现在成为游行的主角。主要场景是任何涉及高延迟的场景。也就是说,在“要求结果”和“获得结果”之间有很多时间。网络请求是高延迟场景中最明显的例子,紧随其后的通常是I/O,然后是CPU限制在另一个核心上的冗长计算 然而,这项技术可能会很好地适应其他场景。例如,考虑编写FPS游戏的逻辑。假设您有一个按钮单击事件处理程序。当玩家点击按钮时,你想鸣笛两秒钟以提醒敌人,然后开门十秒钟。说这样的话不是很好吗
button.Disable();
await siren.Activate();
await Delay(2000);
await siren.Deactivate();
await door.Open();
await Delay(10000);
await door.Close();
await Delay(1000);
button.Enable();
每个任务都在UI线程上排队,因此没有任何任务阻塞,并且每个任务在其任务完成后在正确的位置恢复单击处理程序。GUI时钟就是一个很好的例子;假设你想画一个时钟,它每秒钟更新一次显示的时间。从概念上讲,您希望编写
while true do
sleep for 1 second
display the new time on the clock
用等待MouseEventArgs e = await button.OnMouseDown();
button.Disable();
await siren.Activate();
await Delay(2000);
await siren.Deactivate();
await door.Open();
await Delay(10000);
await door.Close();
await Delay(1000);
button.Enable();
while true do
sleep for 1 second
display the new time on the clock
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace AsyncText
{
class Program
{
static void Main(string[] args)
{
Derived d = new Derived();
TaskEx.Run(() => d.DoStuff()).Wait();
System.Console.Read();
}
public class Base
{
protected string SomeData { get; set; }
protected async Task DeferProcessing()
{
await TaskEx.Run(() => Thread.Sleep(1) );
return;
}
public async virtual Task DoStuff() {
Console.WriteLine("Begin Base");
Console.WriteLine(SomeData);
await DeferProcessing();
Console.WriteLine("End Base");
Console.WriteLine(SomeData);
}
}
public class Derived : Base
{
public async override Task DoStuff()
{
Console.WriteLine("Begin Derived");
SomeData = "Hello";
var x = base.DoStuff();
SomeData = "World";
Console.WriteLine("Mid 1 Derived");
await x;
Console.WriteLine("EndDerived");
}
}
}
}