學而不思則罔,思而不學則殆,溫故而知新。
周末,老婆去上班去了(因為是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 閱讀(1748)
評論(0) 編輯 收藏 引用 所屬分類:
Windows 8