学而不思则罔,思而不学则殆,温故而知新。
周末,老婆去上班去了(因为是2013年元旦,你知道的,休3天,上8天班,今天是上班时间),我们公司休1天,正常周末。闲来无事,想想之前写了好多东西,有时候碰到了又要重新看一遍,效率太低,还是抽个时间整理一下。于是就有了温故知新这一系列的文章。
参考文章: 1. Windows 8 应用程序开发人员博客: 使用Windows 运行时异步性来始终保持应用程序能快速流畅地运行:http://blogs.msdn.com/b/windowsappdev_cn/archive/2012/03/26/windows.aspx 2. Petzold的博客: Asynchronous Processing in Windows 8 http://www.charlespetzold.com/blog/2011/11/Asynchronous-Processing-in-Windows-8.html 3. MSDN WinRT的异步编程,Windows 程序设计这本书的作者说,如果写Windows 8 的书,第一章一定是异步编程(虽然它最后的书第一章不是这个),可见异步编程对于Windows 8 的重要性。本文简单介绍我对异步编程的理解吧,不对的地方请大家指正!欢迎交流。
1.多线程的重要性 From the very early days of Windows programming, application developers realize that they couldn't arbitrary execute a big chunk of lengthly code.
"Windows is a nonpreemptive multitasking environment, and it is important that programs return control to Windows as quickly as possible."(Windows 是一个非抢占式的多任务环境,尽快地将控制权交还给操作系统是非常重要的)
早期的程序员使用Timer->tick或者使用PeekMessage()定期地将控制权交还给系统。
再后来,出现了真正的多线程,和多进程。即使一个进程不会霸占整个操作系统,但是,它还是有时会让自己不能响应外界的交互。举例来说,当你的Word执行一段费事的操作时,你任然可以打开Excel,但你不能同Word交互了。
你可以使用多线程来完成一个需要长时间执行的任务,但是,你不能随意地执行多线程。
每个Windows 程序都有一个UI线程来和用户进行交互,因为这个UI线程非常之重要,Windows框架允许有一个辅助线程,而且Windows的框架有一个排列辅助线程代码的机制,使得这些代码可以运行在UI线程中。
Windows Forms中,Control都有一个BeginInvoke()方法来执行辅助线程。WPF,Silverlight和WinPhone中,每个UI对象都有一个Dispatcher属性,这是一个Dispatcher类对象,该对象都有一个BeginInvoke方法。
Windows 8 中的方法就是使用异步编程了。
2. 异步编程和多线程的区别?
这是我自己的疑惑,我的感觉是,异步编程是在UI线程中存在的概念,是为了实现上面所说的辅助线程用的。只不过在Windows8 中我们不使用显式的BeginInvoke()方法,而是使用了Async方法。不过有时候当一个线程想要操作UI的时候还是需要Dispatcher->RunAsync()方法。
异步编程也是多线程的一种。
3. Windows 8 的UI策略?
Windows 8 的UI讲究快速流畅,程序不能让用户感觉到假死的现象,如果一个UI操作(比如点击按钮代开一个文件)用时超过了50毫秒,那么用户会感觉到卡顿,影响用户体验。微软把这些可能超过50毫秒的方法全部弄成异步的,让他们运行在辅助线程中,保证UI的流畅性。
4. 怎么理解异步?
异步就是回调,讲回调的时候都会举这么一个例子:通过电话为某人提供回拨号码。首先,为他提供回拨号码,然后挂断,做自己爱做的事情,当他把事情处理完毕,通过电话号码拨通你的电话。这就是回调,这也是异步。
5. 异步方法的使用
考虑一下你点击一个按钮,选择打开一个文件。不同于之前的Windows 版本,现在Windows 8 中没有了打开文件夹的对话框,取而代之的是文件选择器(FilePicker),这个玩意在Windows::Storage::Pickers命名空间中。
你要做的就是初始化一个选择器,指定打开文件的后缀名和初始地址,然后调用PickSingleFileAsync()方法。
你已经看到了这个方法以Async结尾,这意味着它是个异步方法,有可能会超过50毫秒。异步方法一般会返回一个IAsyncOperation<T Result>^对象,T是这个方法返回的结果。
如果你的On_Button_Clicked(...)方法中还有其他的代码的话,那么回先执行其他代码,然后,将控制权交给Windows 系统,Windows 系统会使用FilePicker打开一个文件,当打开之后,我们执行then(...)操作,也称为异步方法的延续。
做个实验吧,验证一下异步操作的执行顺序。
1 void Scenario1::PickAFileButton_Click(Object^ sender, RoutedEventArgs^ e)
2 {
3 // Clear previous returned file name, if it exists, between iterations of this scenario
4 rootPage->ResetScenarioOutput(OutputTextBlock);
5
6 if (rootPage->EnsureUnsnapped())
7 {
8 FileOpenPicker^ openPicker = ref new FileOpenPicker();
9 openPicker->ViewMode = PickerViewMode::Thumbnail;
10 openPicker->SuggestedStartLocation = PickerLocationId::PicturesLibrary;
11 openPicker->FileTypeFilter->Append(".jpg");
12 openPicker->FileTypeFilter->Append(".jpeg");
13 openPicker->FileTypeFilter->Append(".png");
14
15 create_task(openPicker->PickSingleFileAsync()).then([this](StorageFile^ file)
16 {
17 if (file)
18 {
19 OutputTextBlock->Text = "Picked photo: " + file->Name;
20 }
21 else
22 {
23 OutputTextBlock->Text = "Operation cancelled.";
24 }
25 }).then([this](task<void> t)
26 {
27 try{
28 t.get();
29 }catch(Platform::Exception^ e)
30 {
31 OutputTextBlock->Text = e->Message;
32 }
33 });
34 for(int i = 0 ; i < 1000000000; i++)
35 {
36 int j = 0;
37 j++;
38 }
39 int k = 0;
40 k++;
41 }
42 }
经过验证,当我们的按钮按下之后,会执行这个长时间的for循环,循环执行完毕之后,才会执行另一个线程。
我们会看到,这里使用了Create_task来包装这个IAsynOperation,Create_task方法给我的感觉就是起一个辅助线程,然后在这个线程中执行打开文件的操作。当我们执行完了PickAFileButton_Click之后,会立即执行Create_task中的方法,这时的控制权就交给了Windows 操作系统,操作系统替我们打开一个FilePicker,我们选定了一个文件之后,执行then操作。可以看到,在这个线程中,我们可以直接操作UI,为什么呢?因为所有在UI线程中执行的异步操作都是在STA中的,单线程环境,所以不用Dispatcher回UI线程中。
在C++中我们使用Create_task().then();的方法,在C#中我们使用await关键字,更方便些。
注意:then([]()->T Result{});中的方法依然是一个异步方法。你可以有多个延续Create_task(IAsyncOperation^ operation).then([](){}).then([](){}).then([](){});
另外,不是所有的异步操作都能执行成功的,我们可以在then中进行异常处理。
所有的东西都被我们可爱的Concurrency::task类包办了,为什么说task类包办了呢?请看下一章,Windows 8 的异步处理(二)可爱的task.then()。你会发现,它简化了我们的很多操作,大家真的应该试一试。
posted on 2013-01-06 15:29
Dino-Tech 阅读(1738)
评论(0) 编辑 收藏 引用 所属分类:
Windows 8