[c#] 編寫自己的異步方法



Answers

實際答案

你可以使用TaskCompletionSource做到這TaskCompletionSource ,它有一個不執行任何代碼的Promise Task ,只有:

“表示未綁定到委託的Task的生產者端,通過Task屬性提供對使用者端的訪問。”

在啟動異步操作時將該任務返回給調用者,並在結束時設置結果(或異常/取消)。 確保操作真的是異步的就在你身上。

這是Stephen Toub的AsyncManualResetEvent實現中所有異步方法的這種根的一個很好的例子:

class AsyncManualResetEvent 
{ 
    private volatile TaskCompletionSource<bool> _tcs = new TaskCompletionSource<bool>();

    public Task WaitAsync() { return _tcs.Task; } 
    public void Set() { _tcs.TrySetResult(true); } 
    public void Reset() 
    { 
        while (true) 
        { 
            var tcs = _tcs; 
            if (!tcs.Task.IsCompleted || 
                Interlocked.CompareExchange(ref _tcs, new TaskCompletionSource<bool>(), tcs) == tcs) 
                return; 
        } 
    } 
}

背景

使用async-await基本上有兩個原因:

  1. 改進的可伸縮性 :當您進行I/O密集型工作(或其他固有的異步操作)時,您可以異步調用它,這樣您就可以釋放調用線程,並且它能夠同時執行其他工作。
  2. 卸載:當您有CPU密集型工作時,可以異步調用它,這會將工作從一個線程移到另一個線程(主要用於GUI線程)。

所以大部分都是。 Net框架的異步調用支持async開箱即用,卸載時使用Task.Run (如示例所示)。 您實際需要自己實現async的唯一情況是創建新的異步調用(例如I/O或異步同步構造 )。

這些案件非常罕見,這就是為什麼你大多找到答案的原因

“只用已有的方法解釋它,只使用async/await模式”

您可以深入了解TaskCompletionSource的本質

Question

我想知道如何以“正確”的方式編寫自己的異步方法。

我看過許多帖子解釋async / await模式,如下所示:

http://msdn.microsoft.com/en-us/library/hh191443.aspx

// Three things to note in the signature: 
//  - The method has an async modifier.  
//  - The return type is Task or Task<T>. (See "Return Types" section.)
//    Here, it is Task<int> because the return statement returns an integer. 
//  - The method name ends in "Async."
async Task<int> AccessTheWebAsync()
{ 
    // You need to add a reference to System.Net.Http to declare client.
    HttpClient client = new HttpClient();

    // GetStringAsync returns a Task<string>. That means that when you await the 
    // task you'll get a string (urlContents).
    Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

    // You can do work here that doesn't rely on the string from GetStringAsync.
    DoIndependentWork();

    // The await operator suspends AccessTheWebAsync. 
    //  - AccessTheWebAsync can't continue until getStringTask is complete. 
    //  - Meanwhile, control returns to the caller of AccessTheWebAsync. 
    //  - Control resumes here when getStringTask is complete.  
    //  - The await operator then retrieves the string result from getStringTask. 
    string urlContents = await getStringTask;

    // The return statement specifies an integer result. 
    // Any methods that are awaiting AccessTheWebAsync retrieve the length value. 
    return urlContents.Length;
}

private void DoIndependentWork()
{
    resultsTextBox.Text += "Working........\r\n";
}

這適用於已經實現此功能的任何.NET方法

  • System.IO操作
  • DataBase操作
  • 網絡相關操作(下載,上傳......)

但是,如果我想編寫自己的方法需要花費相當長的時間來完成哪些方法我可以使用並且重負載在上面示例的DoIndependentWork方法中呢?

在這種方法中,我可以這樣做:

  • 字符串操作
  • 計算
  • 處理我自己的對象
  • 聚合,比較,過濾,分組,處理東西
  • 列出操作,添加,刪除,應對

我再次偶然發現很多帖子,人們只是做了以下事情(再次採用上面的例子):

async Task<int> AccessTheWebAsync()
{ 
    HttpClient client = new HttpClient();

    Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

    await DoIndependentWork();

    string urlContents = await getStringTask;

    return urlContents.Length;
}

private Task DoIndependentWork()
{
    return Task.Run(() => {

        //String manipulations
        //Calculations
        //Handling my own objects
        //Aggregating, comparing, filtering, grouping, handling stuff
        //List operations, adding, removing, coping
    });
}

您可能會注意到更改是DoIndependentWork現在返回一個任務,並且在AccessTheWebAsync任務中該方法得到了await

重負載操作現在封裝在Task.Run() ,這需要它嗎? 如果這就是我需要做的唯一事情就是為我的庫中的每個方法提供異步方法:

public class FooMagic
{
    public void DoSomeMagic()
    {
        //Do some synchron magic...
    }

    public Task DoSomeMagicAsync()
    {
        //Do some async magic... ?!?
        return Task.Run(() => { DoSomeMagic(); });
    }
}

如果你能解釋一下,即使這樣的高投票問題: 如何編寫簡單的異步方法,這將是很好的 只用已經存在的方法解釋它,並且只使用asyn / await模式,就像上面提到的問題的註釋一樣,它指出了: 如何編寫簡單的異步方法?




Links