博客 / 詳情

返回

在實際應用中,異步線程可能需要等待另外的任務完成情況來確定本任務的完成狀態。例如圖像分析的結果,依賴於圖像分析算法對圖像的分析,在這種情況下,圖像分析並非一種返回結果,根據分析返回的結果來確認圖像是好的,還是壞的,進而手動設置異步線程的結果。今天我們以一個簡單的小例子,簡述在.NET開發中,如何通過TaskCompletionSource來手動設置異步線程的等待結果,僅供學習分享使用,如有不足之處,還請指正。

image

 

TaskCompletionSource概述

 

TaskCompletionSource<TResult> 是 .NET 中用於手動控制 Task<TResult> 完成時機的工具,常用於將事件驅動或回調模式轉換為 async/await 友好形式。TaskCompletionSource有一個屬性Task,用於獲取當前需要等待的任務。通過TaskCompletionSource,可以設置三種返回結果,如下所示:

  • SetCanceled:將TaskCompletionSource.Task 轉換為Cancel狀態,並在原等待任務中拋出TaskCanceledException異常。
  • SetException:將TaskCompletionSource.Task 轉換為Faluted狀態,並在原等待任務中拋出對應的Exception異常。
  • SetResult:將TaskCompletionSource.Task 轉換為RanToCompletion狀態,並設置TResult類型的結果。
  • TrySetCanceled:嘗試將TaskCompletionSource.Task 轉換為Canceled狀態,,並在原等待任務中拋出TaskCanceledException異常。
  • TrySetException:嘗試將TaskCompletionSource.Task 轉換為Faluted狀態,並在原等待任務中拋出對應的Exception異常。
  • TrySetResult:將TaskCompletionSource.Task 轉換為RanToCompletion狀態,並設置TResult類型的結果。

對於上述設置方法,在調用時有以下兩點需要注意:

  • 對於SetCanceled,SetException,SetResult方法,如果當前Task狀態已經是RanToCompletion,Faulted,Canceled,則在設置時拋出InvalidOperationException。
  • 對於TrySetCanceled,TrySetException,TrySetResult,如果Task已經是RanToCompletion,Faulted,Canceled,則返回false,否則返回true。

在上述TaskCompletionSource設置返回結果的方法中,涉及到當前Task對應的狀態,對於一個Task類型的任務,主要有以下幾種:

  • Created‌:任務已創建但尚未啓動。
  • ‌WaitingForActivation‌:任務已創建但未被激活(例如通過Start方法)。
  • ‌WaitingToRun‌:任務已激活但尚未開始執行。
  • ‌Running‌:任務正在執行中。
  • ‌WaitingForChildrenToComplete‌:任務本身已完成,但其子任務仍在運行(僅適用於父任務)。
  • ‌RanToCompletion‌:任務已成功完成。
  • ‌Canceled‌:任務因取消操作終止。
  • ‌Faulted‌:任務因未處理異常終止。 ‌

Task的主要屬性,如下所示:

  • ‌Task.Status‌:獲取當前任務的TaskStatus值。 ‌
  • ‌IsCanceled‌:檢查任務是否因取消完成。 ‌
  • ‌IsFaulted‌:檢查任務是否因異常完成。 
  • ‌IsCompleted‌:檢查任務是否已完成(無論成功、取消或異常)。 ‌

 

TaskCompletionSource用法

 

接下來,以一個簡單的小例子介紹TaskCompletionSource的使用方法,首先創建的一個任務異步執行Running方法,並在Running方法中等待TaskCompletionSource.Task的完成和獲取結果,如下所示:

private Task task;

private TaskCompletionSource<bool> tcs;

public MainForm()
{
    InitializeComponent();
}

private void btnStart_Click(object sender, EventArgs e)
{
    tcs = new TaskCompletionSource<bool>();
    task = Task.Run(async () =>
    {
        await Running(this.tcs);
    });

}

private async Task Running(TaskCompletionSource<bool> tcs)
{
    try
    {
        this.OutputInfo("當前開始工作中");
        bool result = await tcs.Task;
        this.OutputInfo($"當前已完成工作,IsComplete={tcs.Task.IsCompleted},結果為{result}");
    }
    catch (TaskCanceledException ex)
    {
        this.OutputInfo($"當前已取消工作,IsCancelled = {tcs.Task.IsCanceled}");
        this.OutputInfo($"異常信息如下:");
        this.OutputInfo($"{ex.Message}");
    }
    catch (Exception ex2)
    {
        this.OutputInfo($"當前工作出現了異常,IsFaulted={tcs.Task.IsFaulted}");
        this.OutputInfo($"異常信息如下:");
        this.OutputInfo($"{ex2.Message}");
    }
}

 

設置Result

 

當任務正常完成時,通過調用SetResult或TrySetResult方法,將任務狀態轉換為RanToCompletion,Running方法中的任務正常完成。此方法接收一個參數,用於設置Task返回的結果,類型由定義TaskCompletionSource時指定的泛型確定,如下所示:

private void btnEnd_Click(object sender, EventArgs e)
{
	if (this.tcs != null && this.tcs.Task.Status==TaskStatus.WaitingForActivation)
	{
		this.tcs.SetResult(true);
	}
}

 

設置Canceled

 

當任務被取消時,通過調用SetCanceled或TrySetCanceled方法,將任務狀態轉換為Canceled,此時Running方法中的任務將拋出TaskCanceledException,如下所示:

private void btnCancel_Click(object sender, EventArgs e)
{
	if (this.tcs != null && this.tcs.Task.Status == TaskStatus.WaitingForActivation)
	{
		this.tcs.SetCanceled();
	}
}

 

設置Exception

 

當任務執行過程中出現異常時,通過調用SetException或TrySetException方法,將任務狀態轉換為Faluted,此時Running方法總的任務將拋出對應設置的Exception,如下所示:

private void btnExce_Click(object sender, EventArgs e)
{
	if (this.tcs != null && this.tcs.Task.Status == TaskStatus.WaitingForActivation)
	{
		this.tcs.SetException(new Exception("Okcoder異常出現"));
	}
}

在上述方法中,引用的Output方法為自定義方法,用於將信息輸出到文本框中,如下所示:

private void OutputInfo(string msg)
{
	this.Invoke(() =>
	{
		this.txtInfo.AppendText($"{msg}\r\n");
	});
}

 

示例演示

 

在本示例中,首先有一個開始按鈕,用於啓動任務:

image

結束按鈕,用於設置正常的任務結束,並返回結果

image

一個取消按鈕,用於取消任務

image

一個異常按鈕,用於設置運行過程中出現的異常信息

image

以上就是《推薦一種手動設置異步線程等待機制的解決方案》的全部內容,旨在拋磚引玉,一起學習,共同進步!

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.