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

wangccsy發表於2018-12-22

保持在後臺
Windows執行時實現中的一些FileHelper方法有多個等待運算子來處理一系列非同步呼叫。這是有道理的:流程中的每個步驟必須在下一步執行之前完成。但是,等待的一個特徵是它在與其呼叫的相同執行緒而不是後臺執行緒上恢復執行。當您獲得更新使用者介面的結果時,這通常很方便。但是,在FileHelper實現的方法中,這不是必需的。 WriteTextAsync和ReadTextAsync方法體內的所有內容都可以在輔助執行緒中出現。
Task類有一個名為ConfigureAwait的方法,可以控制等待恢復的執行緒。如果將false引數傳遞給ConfigureAwait,則完成的任務將在用於實現該函式的同一工作執行緒上恢復。如果您想在FileHelper程式碼中使用它,則需要使用AsTask將Windows執行時方法返回的IAsyncAction和IAsyncOperation物件轉換為任務,然後在該Task物件上呼叫ConfigureAwait。
例如,以下是現有Xamarin.FormsBook.Platform.WinRT專案中WriteTextAsync和ReadTextAsync方法的實現方法:

namespace Xamarin.FormsBook.Platform.WinRT
{
    class FileHelper : IFileHelper
    {
        __
        public async Task WriteTextAsync(string filename, string text)
        {
            StorageFolder localFolder = ApplicationData.Current.LocalFolder;
           IStorageFile storageFile = await localFolder.CreateFileAsync(filename, 
            CreationCollisionOption.ReplaceExisting);
            await FileIO.WriteTextAsync(storageFile, text);
        }
        public async Task<string> ReadTextAsync(string filename)
        {
            StorageFolder localFolder = ApplicationData.Current.LocalFolder;
            IStorageFile storageFile = await localFolder.GetFileAsync(filename);
            return await FileIO.ReadTextAsync(storageFile);
        }
        __
    }
}

這些方法各有兩個等待運算子。 為了使這些方法更有效,您可以使用AsTask和ConfigureAwait將它們更改為:

namespace Xamarin.FormsBook.Platform.WinRT
{
    class FileHelper : IFileHelper
    {
        __
        public async Task WriteTextAsync(string filename, string text)
        {
            StorageFolder localFolder = ApplicationData.Current.LocalFolder;
            IStorageFile storageFile = await localFolder.CreateFileAsync(filename, 
                                                  CreationCollisionOption.ReplaceExisting).
                                                  AsTask().ConfigureAwait(false);
            await FileIO.WriteTextAsync(storageFile, text).AsTask().ConfigureAwait(false);
        }
        public async Task<string> ReadTextAsync(string filename)
        {
            StorageFolder localFolder = ApplicationData.Current.LocalFolder;
            IStorageFile storageFile = await localFolder.GetFileAsync(filename).
                                                AsTask().ConfigureAwait(false);
            return await FileIO.ReadTextAsync(storageFile).AsTask().ConfigureAwait(false);
        }
        __
    }
}

現在,第一個await運算子之後的方法在工作執行緒中執行,而await不需要切換回使用者介面執行緒只是為了繼續該方法。 當使用await從TextFileAsyncPage呼叫這些方法時,會切換回使用者介面執行緒。
您可能希望將此技術限制為底層庫函式,或者包含一系列不訪問使用者介面物件的await運算子的頁面類中的程式碼。 對於只包含一個從使用者介面執行緒呼叫的await運算子的函式,該技術沒有多大意義,因為切換回使用者介面執行緒必須在某個時間發生,如果不是 發生在庫函式中,它將發生在呼叫庫函式的程式碼中。


相關文章