声明:这是一片翻译自http://www.charlespetzold.com/blog/2011/11/Asynchronous-Processing-in-Windows-8.html的科技文章,翻译的很浅显,如有不当之处,请联系我,谢谢! 转帖请注明出处! Windows 8刚刚兴起,但是其中涉及的技术显然已经存在或者有相似的资料可以参考。这篇文章讲述了Windows 8的新特性:异步处理。我们都知道Windows采用了多线程,当打开一个word需要很长时间的时候,这个word程序就像假死一样,然而你可以去打开一个excel,这就是多线程。但是Windows 8做得更绝,它不允许一个程序假死,采用的方法就是异步。 下面就是翻译的文章,翻译不当之处请大家指正。 Windows 8 中的异步操作一本典型的关于windows 8的书看起来肯定会有些奇怪。不像其他的windows编程的书都从hello world开始,windows 8的故事开始于“异步处理”
来点背景知识:很久很久以前,编写windows程序的时候,程序员意识到,他们不能任意地执行一段很长很长的代码。在大师第一版的《Windows程序设计》中写道“Windows是一种非抢占式的多任务环境,程序很快地将控制权交还给系统是很重要的”。但是,一个程序就可以霸占整个操作系统。在那些日子里,一个要完成很长很长任务的程序不得不被分隔成很多小块执行,要么通过timer要么通过PeekMessage定期地将控制权交还给操作系统。
后来windows搞出了真正的多任务和多线程,但是这个问题还是存在。即使一个程序不能霸占整个操作系统,但是至少,在原理上来讲,他还是霸占了它自己,而且导致不能响应用户输入。当你打开一个word的时候,卡住了,但是你可以打开其他excel然而你的word不论你怎么点,都还是没有半点反应。程序希望这些很长的工作拆分成很多次要线程,这些次要线程在后台处理就好了。
然而,Windows编程不能完全自由地创建次要线程。对于一些特殊的窗口,他们可能只有一个线程来处理用户的输入,包括鼠标键盘之类的,然后显示点图片跟用户交互。这个“UI thread"因此对于Windows应用程序来说非常非常的重要,因为所有和用户的交互都要仰仗这个线程。在Windows表格中,空间定义了一个BeginInvoke方法来达到这个目的。在WPF,Silverlight,Windows Phone中,每一个UI对象都有一个Dispetcher属性,它是一个具有BeginInvoke方法的类型为Dispatcher的对象。
来到了windows 8 时代,很多Windows UI和API都与起初的1985年的Windows有了很大的更新。Windows 8 的UI试图做到“快速并且流线”,一个没有相应的Windows 8 程序被称为一个坏掉的程序。
设想如果有个人跟你说,你的应用程序因为要在UI线程上执行超过50毫秒的程序而被禁止。如果你你有那么一段代码在你的应用程序中,你需要把这些代码转移到次要线程中去。你可能不会高兴。
好吧,这就是windows 8 程序员强加给自己的规则。WinRT有一堆类,也有一大堆的方法。一个Windows 8 程序需要在UI线程中调用这些方法,如果这些方法都耗费很长的执行时间的话,那么他们肯定会block住UI线程而导致应用程序不能被响应。这对Windows 8的初衷来说是相悖的。
结果显示,有那么10%---15%的WinRT方法会需要超过50毫秒的时间,过了这50毫秒,你的应用程序才会获得控制权。为了阻止这些可恶的方法霸占一个应用程序,他们想到了异步。
来个例子吧,考虑一个方法OpenFile。你传递给这个方法一个文件名,然后这个方法打开一个文件,然后返回某个类型的handle或者stream。因为这个函数要敲击桌面,它可能会需要超过50毫秒的时间来执行。这意味着,这个函数是做成一个异步方法的获选。
我们把这个方法改成异步的,很简单,后面加上Async。(每个Windows 8 的异步方法都是以Async结尾的)注意,这个方法不返回一个handle或者一个stream,而是返回一个被称为“operation”或者“future"或者”promis“的一个对象来打开文件。利用这个对象,应用程序指定一个回调函数使得当你打开文件这个操作完成时被调用。然后,应用程序调用start()方法(是operation对象的方法)。调用了这个方法之后呢,应用程序就把控制权交回给了Windows即操作系统,不会block住UI线程了,而且OpenFileAsync就可以干它自己的事情了。当你已经完成了打开文件的操作时,OpenFileAsync就会调用我们之前设置的回调函数,此时应用程序已经获得了文件的handle或者stream。
就像我说的,一些API调用在Windows 8中都是这个原理。对于应用程序的程序员来说,处理所有的这些异步方法明显听起来有点强人所难。然而,它被做的灰常简单,部分地标准化和形式化所有的异步方法调用,更多地把这些复杂的语法交给编译器利用两个新的C#5.0关键字await和async。(VB同样)
这个东西对windows 8来说实在不能被叫做新东西。在2010年10月份,基于.Net Task<T>的异步处理就在CTP(Community Technology Preview)中出现了,现在第三版的AsyncCTP也已经出现。这个 Async CTP不是Windows 8中实现的,但是很相似,所以有很多现成的东西,在The Task-Based Asynchronous Pattern中,一篇我朋友兼作家Setphen Toub写的文章,还有Eric Lippert,Mads Torgersen,Stephen Toub在October issue of MSDN Magazine中发表的三篇论文(包括cover story)。再次强调,这些文章不是关于Windows 8异步方法的,但 无论如何他们的见解是很独特的。此外,这种对异步的支持是.Net的子集,而它更是windows 8 的一部分,所以你可以利用这些技术在你的Windows 8程序中。
因此,可以说Windows 8 支持两种异步处理模式,一种是从.NET继承,一种是针对Windows Runtime。他们在概念上很相似,仅仅在细节上有些不同而已。
你有可能在一个很小的Windows 8 程序中邂逅异步方法,这太神奇了。假设你想写一个程序,点一下按钮,弹出一个打开文件的对话框,让你选择一幅图片。随后这个程序读取这个图片文件,并利用Image元素显示出来。WinRT在Windows::Storage::Pickers命名空间中包含了一个FileOpenPicker类取代file-open对话框。你实例化这个类,制定你想要打开的文件后缀名,和你想从哪个文件开始打开,然后调用PickSingleFileAsync 方法。
注意这个方法名:PickSingleFileAsync以Async结尾,看到这个,你就知道这是个异步方法。这个方法不直接引起file-open picker显示,因为file-open picker需要询问文件系统,而且这可能会花费超过50毫秒的时间。
取而代之的是,PickSingleFileAsync返回一个PickSingleFileOperation的对象(所有的异步方法都返回一个以operation结尾的对象)。这个operation类实现了IAsyncOperation<StorageFile>接口。这个StorageFile类型很重要,因为这是PickSingleFileAsync函数最终返回给你程序的,但是不是现在。
IAsyncOperation<T>从IAsyncInfo接口继承,IASyncInfo定义了Start,Cance和Close方法,还有Id,Status,ErrorCode属性。IAsyncOperation<T>又添加了Completed属性。Completed是一个回调函数的代理这个回调函数是你必须要设定的。当你的程序设置了Completed的回调函数后,就要调用Start方法。你的程序就要返回控制权给系统了。
当Windows选定了一个文件给你的程序的后,回调函数被调用,然后在回调函数中调用GetResults,返回一个StorageFile类型的对象。
一旦你的程序获得了一个StorageFile对象,就和用户选择的文件联系起来了,你可以以只读方式打开这个文件,函数名是:OpenAsync,哦吼,又一个Async方法!
我们先看看一些代码吧,下面的不同于原文,是用C++写的,可以保证运行:
1 void SimpleSample::MainPage::ImageButton_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
2 {
3
4 FileOpenPicker^ open = ref new FileOpenPicker();
5 // Select display mode
6 open->ViewMode = PickerViewMode::Thumbnail;
7 // Start location
8 open->SuggestedStartLocation = PickerLocationId::Desktop;
9
10 open->FileTypeFilter->Append(".jpg");
11 open->FileTypeFilter->Append(".jpeg");
12 open->FileTypeFilter->Append(".png");
13 open->FileTypeFilter->Append(".bmp");
14
15 // Instantiate a operation and Start.
16 PickSingleFileOperation^ pickOperation = open->PickSingleFileAsync();
17 pickOperation->Completed = ref new AsyncOperationCompletedHandler<StorageFile^>([this] (IAsyncOperation<StorageFile^>^ operation)
18 {
19 StorageFile^ file = operation->GetResults();
20
21 if(file)
22 {
23 StreamRetrievalOperation^ StreamOperation = file->OpenAsync(FileAccessMode::Read);
24 StreamOperation->Completed = ref new AsyncOperationCompletedHandler<IRandomAccessStream^>([this](IAsyncOperation<IRandomAccessStream
25 ^>^ operation)
26 {
27 IRandomAccessStream^ bitmapStream = operation->GetResults();
28 BitmapImage^ bitmapImage = ref new BitmapImage();
29 bitmapImage->SetSource(bitmapStream);
30 ShowImage->Source = bitmapImage;
31 });
32 StreamOperation->Start();
33 }
34 });
35 pickOperation->Start();
36
37
38
39 }
处理按钮按下的方法实例化初始化了一个FileOpenPicker然后调用了PickSingleFileAsync方法,这个方法返回了一个PickSingleFileOperation类型的对象。AsyncOperationCompletedHandler被设置为completed属性,最后面调用strat()方法。如果:ImageButton_Click还有其他事情要做,这些代码将会在异步方法开始前被执行。
当:ImageButton_Click返回了控制权给Windows之后的某个时间里,file-open 界面显示出来。在这期间,其他在程序中代码可以运行。当用户无视这个picker的话(例如选择了一个文件或者按下了Cancel按钮),AsyncOperationCompletedHandler回调函数被调用。尽管参数设置成了IAsyncOperation<StorageFile>,但是,他是跟PickSingleFileOperation是一样的。调用GetResults获得StorageFile对象。如果是null,意味着用户取消了picker。
另外,程序需要继续它的第二个异步方法。这就是新的SrorageFile的OpenAsync方法。返回一个StreamRetrievalOperation对象。设置Completed然后调用Start。当操作完成时,AyncOperationCompletedHandler回调函数调用,GetResults方法返回一个IRandomAccessStream类型的对象。
C#中有await和async关键字,可以把这一过程简化,不过微软的官方文档上面显示,现在是pre-beta版本,我们需要直接操作IAsyncOperation,到了Beta版本,我们似乎就可以简化这个操作了。期待吧,少年们。
posted on 2012-02-14 10:51
Dino-Tech 阅读(1190)
评论(1) 编辑 收藏 引用