第二十章:非同步和檔案I/O.(一)

wangccsy發表於2018-11-12

圖形使用者介面具有一點點特性,具有深遠的影響:必須按順序處理使用者對應用程式的輸入。無論使用者輸入事件是來自鍵盤,滑鼠還是觸控,每個事件必須由應用程式完全處理 – 直接或通過使用者介面物件(如按鈕或滑塊) – 在應用程式獲得下一個使用者之前 – 來自作業系統的輸入事件。
經過一些反思後,這個限制背後的基本原理變得清晰,可能是一個例子:假設一個頁面包含兩個按鈕,使用者可以快速點選一個然後另一個按鈕。這兩個按鈕可能會在兩個獨立的執行執行緒中同時處理這兩個分接頭嗎?不,那不行。可能是第一個按鈕改變了第二個按鈕的含義,可能完全禁用它。因此,在第二個按鈕開始處理自己的點選之前,必須允許第一個按鈕完全處理其點選。
此限制的後果非常嚴重:必須在單個執行執行緒中處理對特定應用程式的所有使用者輸入。而且,使用者介面物件通常不是執行緒安全的。無法從輔助執行執行緒修改它們。因此,與應用程式的使用者介面連線的所有程式碼僅限於一個執行緒。此執行緒稱為主執行緒或使用者介面執行緒或UI執行緒。
幾十年來,隨著使用者越來越習慣於圖形使用者介面,我們越來越不能容忍即使是最輕微的響應性失誤。作為應用程式設計師,我們因此盡力保持使用者介面響應以實現最大的使用者滿意度。這意味著在UI執行緒上執行的任何內容都必須儘快執行其處理並將控制權返回給作業系統。如果在UI執行緒中執行的事件處理程式在長處理作業中陷入困境,整個使用者介面似乎會凍結並且肯定會使使用者煩惱。
因此,應用程式必須執行的任何冗長的作業都應該降級為執行的輔助執行緒,通常稱為工作執行緒。據說這些工作執行緒“在後臺執行”並且不會干擾UI執行緒的響應性。
你已經在本書中看到了一些例子。幾個示例程式 – 第13章中的ImageBrowser和BitmapStreams程式,“點陣圖”,以及第19章“集合檢視”中的SchoolOfFineArt庫和RssFeed程式 – 使用WebRequest類通過Internet下載檔案。對WebRequest的BeginGetResponse方法的呼叫啟動了一個非同步訪問Web資源的工作執行緒。 WebRequest呼叫快速返回,程式可以在下載檔案時處理其他使用者輸入。 BeginGetResponse的引數是在後臺程式完成時呼叫的回撥方法。在此回撥方法中,程式呼叫EndGetResponse來訪問下載的資料。
但傳遞給BeginGetResponse的回撥方法有一點問題。回撥方法在下載檔案的同一工作執行緒中執行,在一般情況下,您無法從UI執行緒以外的任何其他方式訪問使用者介面物件。通常,這意味著回撥方法必須訪問UI執行緒。 Xamarin.Forms支援的三個平臺中的每一個都有自己的本機方法,用於從UI執行緒上的輔助執行緒執行程式碼,但在Xamarin.Forms中,這些都可以通過Device.BeginInvokeOnMainThread方法獲得。 (但是,您會記得,通常有一些與ViewModel相關的異常:雖然輔助執行緒無法直接訪問使用者介面物件,但輔助執行緒可以設定通過使用者介面物件繫結的屬性資料繫結。)
近年來,非同步處理在程式設計師變得更容易的同時變得越來越普遍。這是一個持續的趨勢:計算的未來無疑將涉及更多的非同步計算和並行處理,特別是隨著多核處理器晶片的使用越來越多。開發人員需要良好的作業系統支援和語言工具來處理非同步操作,幸運的是.NET和C#一直處於這種支援的最前沿。
本章將探討在Xamarin.Forms應用程式中使用非同步處理的一些基礎知識,包括使用.NET Task類來幫助您定義和使用非同步方法。使用C#5.0中引入的兩個關鍵字:async和await,大大減輕了處理回撥函式的習慣麻煩。 await運算子通過簡化非同步呼叫的語法,澄清非同步呼叫的程式流,通過簡化使用者介面物件的訪問,簡化工作執行緒引發的異常處理,以及統一處理非同步呼叫,徹底改變了非同步程式設計的語法。這些例外和取消後臺工作。
本章主要演示如何使用非同步處理來執行檔案輸入和輸出,以及如何建立自己的工作執行緒以執行冗長的作業。
但是Xamarin.Forms本身包含幾種非同步方法。


相關文章