資料流程 (工作平行程式庫)
工作平行程式庫 (TPL) 提供資料流程元件,協助讓啟用並行的應用程式更強固。 這些資料流程元件合稱為「TPL 資料流程程式庫」。 此資料流程模型以提供針對廣泛資料流程以及管線工作的同處理序訊息傳遞,將以行動為基礎的程式撰寫升級。 資料流程元件會在 TPL 的類型與排程基礎結構上建置,並整合 C#、Visual Basic 以及 F# 語言對非同步程式設計的支援。 當您有多個必須非同步式互相溝通的作業時,或當您因為資料變為可用而要處理資料時,這些資料流程元件就會相當實用。 例如,請考慮一個應用程式,它會處理來自網路攝影機的影像資料。 使用資料流模型,應用程式就可以在影像畫面可用時處理它們。 例如,如果應用程式因執行光源修正或消除紅眼而增強影像畫面,則您可以建立資料流程元件的「管線」。 此管線的每個階段都可能使用更廣泛的平行處理原則功能 (例如 TPL 提供的功能) 來轉換該影像。
本文件提供 TPL 資料流程程式庫的概觀。 此文件描述程式設計模型、預先定義的資料流程區塊類型,以及描述如何設定資料流程區塊以符合應用程式的特定需求。
注意
TPL 資料流程程式庫 (System.Threading.Tasks.Dataflow 命名空間) 並未隨 .NET 散發。 若要在 Visual Studio 中安裝 System.Threading.Tasks.Dataflow 命名空間,請開啟您的專案,從 [專案] 功能表中選擇 [管理 NuGet 套件],並於線上搜尋 System.Threading.Tasks.Dataflow
套件。 除此之外也可使用 .Net Core CLI (執行 dotnet add package System.Threading.Tasks.Dataflow
) 加以安裝。
程式設計模型
TPL 資料流程程式庫提供了訊息傳遞之基礎,也是平行處理具有高輸送量與低延遲、需要大量 CPU 與 I/O 的應用程式之基礎。 這也可以讓您明確地控制資料如何緩衝以及如何在系統中移動。 若要進一步了解資料流程程式撰寫模型,請考慮以非同步方式從磁碟載入影像並建立這些影像組合的應用程式。 傳統的程式設計模型通常需要您使用回呼和同步處理物件 (例如鎖定),來協調工作與存取共用資料。 您可以使用資料流程程式撰寫模型來建立資料流程物件,從磁碟讀取影像時,該資料流程物件可以處理影像。 在資料流程模型下,您宣告資料的處理方式、宣告其可使用的時機,以及資料之間的相依性。 由於執行階段會處理資料之間的相依性,您通常可以避免存取共用資料之同步處理的需求。 此外,因為執行階段排程是依據資料的非同步抵達來運作,所以資料流程可以藉由有效管理基礎執行緒以改善回應性和輸送量。 如需在 Windows Forms 應用程式中使用資料流程程式撰寫模型來實作影像處理的範例,請參閱逐步解說:在 Windows Forms 應用程式中使用資料流程。
來源和目標
TPL 資料流程程式庫由「資料流程區塊」所組成,其為緩衝及處理資料的資料結構。 TPL 定義三種資料流程區塊:「來源區塊」、「目標區塊」和「傳播程式區塊」。 來源區塊可當做資料來源,可以從中讀取。 目標區塊可當做資料接收器,可以寫入。 傳播程式區塊可當做來源區塊和目標區塊,而且可以從中讀取和寫入。 TPL 定義 System.Threading.Tasks.Dataflow.ISourceBlock<TOutput> 介面代表來源、System.Threading.Tasks.Dataflow.ITargetBlock<TInput> 代表目標,以及 System.Threading.Tasks.Dataflow.IPropagatorBlock<TInput,TOutput> 代表傳播程式。 IPropagatorBlock<TInput,TOutput> 繼承自 ISourceBlock<TOutput> 和 ITargetBlock<TInput>。
TPL 資料流程程式庫提供幾種預先定義的資料流程區塊類型,這些類型會實作 ISourceBlock<TOutput>、ITargetBlock<TInput> 和 IPropagatorBlock<TInput,TOutput> 介面。 本文件的預先定義的資料流程區塊類型一節描述這些資料流程區塊類型。
連接區塊
您也可以連接資料流程區塊來形成「管線」(資料流程區塊的線性序列) 或「網路」(資料流程區塊的圖形)。 管線是網路的一種格式。 在管線或網路中,當資料可供使用時,來源會非同步散佈資料至目標。 ISourceBlock<TOutput>.LinkTo 方法將來源資料流程區塊連結至目標區塊。 來源可以連接至零或多個目標;目標可以從零或更多個來源連接。 您可以同時在管線或網路中加入或移除資料流程區塊。 預先定義的資料流程區塊類型會處理連結和取消連結的所有執行緒安全性層面。
如需連接資料流程區塊以形成基本管線的範例,請參閱逐步解說:建立資料流程管線。 如需連接資料流程區塊以形成更複雜網路的範例,請參閱逐步解說:在 Windows Forms 應用程式中使用資料流程。 如需在來源提供目標訊息後將目標從來源取消連結的範例,請參閱如何:取消連結資料流程區塊。
篩選
當您呼叫 ISourceBlock<TOutput>.LinkTo 方法來連結來源與目標時,您可以提供委派,根據訊息值來判斷目標區塊接受或拒絕訊息。 篩選機制是確保資訊流程區塊只接收特定值的實用方式。 對於大部分預先定義的資料流程區塊類型而言,如果來源區塊連接到多個目標區塊,則當目標區塊拒絕訊息時,來源就會提供該訊息給下一個目標。 來源提供訊息給目標的順序是由該來源所定義,而且可能會根據該來源類型而有所不同。 大部分的來源區塊類型在目標接受訊息之後,就會停止提供訊息。 此規則的唯一例外是 BroadcastBlock<T> 類別,即使有一些目標拒絕了訊息,其仍為所有目標提供每一個訊息。 如需使用篩選來只處理特定訊息的範例,請參閱逐步解說:在 Windows Forms 應用程式中使用資料流程。
重要
由於每個預先定義來源資料流程區塊類型確保訊息都會按照收到訊息的順序來散佈,所以每個訊息都必須由來源區塊所讀取,之後來源區塊才可處理下一個訊息。 因此,當您使用篩選以連接多個目標至來源時,請確定至少有一個目標區塊會接收每一個訊息。 否則,您的應用程式可能會發生死結。
訊息傳遞
資料流程程式設計模型與「訊息傳遞」的概念有關,其中程式的獨立元件可藉由傳送訊息相互通訊。 在應用程式元件之間散佈訊息的其中一種方式,為呼叫 Post (同步的) 和 SendAsync (非同步) 方法,來將訊息傳送至目標資料流程區塊,以及 Receive、ReceiveAsync 和 TryReceive 方法,以接收來自來源區塊的訊息。 您可以傳送輸入資料至管線的前端節點 (目標區塊),以及從管線的終端節點或網路 (一個或多個來源區塊) 的終端節點接收輸出資料,將這些方法結合資料流程管線或網路。 您也可以使用 Choose 方法,從第一個具有可用資料並在此資料中執行動作之提供的來源讀取。
來源區塊會呼叫 ITargetBlock<TInput>.OfferMessage 方法,以提供資料給目標區塊。 目標區塊對於所提供的訊息會採取三種回應之一:它可以接受該訊息、拒絕該訊息或延後該訊息。 當目標接受該訊息時,OfferMessage 方法會傳回 Accepted。 當目標拒絕該訊息時,OfferMessage 方法會傳回 Declined。 當目標要求不再接收來自來源的任何訊息時,OfferMessage 會傳回 DecliningPermanently。 在接收這類傳回值之後,以及從這類目標自動取消連結之後,預先定義的來源區塊類型就不會傳遞訊息給連結的目標。
當目標區塊延後該訊息以供稍後使用時,OfferMessage 方法會傳回 Postponed。 延後訊息的目標區塊可以於稍後呼叫 ISourceBlock<TOutput>.ReserveMessage 方法,以嘗試保留所提供的訊息。 此時訊息仍為可用,而且可由目標區塊所使用,或者訊息已由另一個目標所採用。 當目標區塊於稍後要求此訊息,或者不再需要此訊息時,便會分別呼叫 ISourceBlock<TOutput>.ConsumeMessage 或 ReleaseReservation 方法。 訊息保留通常由在非窮盡模式下操作的資料流程區塊型別所使用。 本文稍後將說明非窮盡模式。 除了保留已延後的訊息之外,目標區塊也可以使用 ISourceBlock<TOutput>.ConsumeMessage 方法,來嘗試直接使用其他延後的訊息。
資料流程區塊的完成
資料流程區塊也支援「完成」的概念。 在已完成狀態中的資料流程區塊並不會執行任何進一步的工作。 每個資料流程區塊都具有相關聯的 System.Threading.Tasks.Task 物件,稱為完成工作,代表該區塊的完成狀態。 由於您可以使用完成工作來等候 Task 物件結束,所以可以等候資料流程網路的一或多個終端節點完成。 IDataflowBlock 介面定義了 Complete 方法,該方法會通知為其所要求的資料流程區塊完成,以及定義了 Completion 屬性,該屬性會傳回資料流程區塊的完成工作。 ISourceBlock<TOutput> 和 ITargetBlock<TInput> 這兩者都是繼承自 IDataflowBlock 介面。
有兩種方式用來判斷資料流程區塊是否完成而沒有錯誤,還是遇到一或多個錯誤或已取消。 第一種方式為在 try
-catch
區塊 (在 Visual Basic 中為 Try
-Catch
) 中的完成工作上呼叫 Task.Wait 方法。 下列範例會建立一個會在其輸入值小於零時擲回 ArgumentOutOfRangeException 的 ActionBlock<TInput> 物件。 當這個範例呼叫完成工作上的 Wait 時,會擲回 AggregateException。 可透過 AggregateException 物件的 InnerExceptions 屬性存取 ArgumentOutOfRangeException。
// Create an ActionBlock<int> object that prints its input
// and throws ArgumentOutOfRangeException if the input
// is less than zero.
var throwIfNegative = new ActionBlock<int>(n =>
{
Console.WriteLine("n = {0}", n);
if (n < 0)
{
throw new ArgumentOutOfRangeException();
}
});
// Post values to the block.
throwIfNegative.Post(0);
throwIfNegative.Post(-1);
throwIfNegative.Post(1);
throwIfNegative.Post(-2);
throwIfNegative.Complete();
// Wait for completion in a try/catch block.
try
{
throwIfNegative.Completion.Wait();
}
catch (AggregateException ae)
{
// If an unhandled exception occurs during dataflow processing, all
// exceptions are propagated through an AggregateException object.
ae.Handle(e =>
{
Console.WriteLine("Encountered {0}: {1}",
e.GetType().Name, e.Message);
return true;
});
}
/* Output:
n = 0
n = -1
Encountered ArgumentOutOfRangeException: Specified argument was out of the range
of valid values.
*/
' Create an ActionBlock<int> object that prints its input
' and throws ArgumentOutOfRangeException if the input
' is less than zero.
Dim throwIfNegative = New ActionBlock(Of Integer)(Sub(n)
Console.WriteLine("n = {0}", n)
If n < 0 Then
Throw New ArgumentOutOfRangeException()
End If
End Sub)
' Post values to the block.
throwIfNegative.Post(0)
throwIfNegative.Post(-1)
throwIfNegative.Post(1)
throwIfNegative.Post(-2)
throwIfNegative.Complete()
' Wait for completion in a try/catch block.
Try
throwIfNegative.Completion.Wait()
Catch ae As AggregateException
' If an unhandled exception occurs during dataflow processing, all
' exceptions are propagated through an AggregateException object.
ae.Handle(Function(e)
Console.WriteLine("Encountered {0}: {1}", e.GetType().Name, e.Message)
Return True
End Function)
End Try
' Output:
' n = 0
' n = -1
' Encountered ArgumentOutOfRangeException: Specified argument was out of the range
' of valid values.
'
這個範例示範在執行資料流程區塊的委派中有例外狀況未受處理的案例。 建議您在這類區塊的主體中處理例外狀況。 然而,假如您無法這樣做,區塊會表現得就像已經取消,而不會處理傳入的訊息。
當資料流程區塊已明確地取消時,AggregateException 物件包含 InnerExceptions 屬性中的 OperationCanceledException。 如需取消資料流程的詳細資訊,請參閱啟用取消一節。
第二種判斷資料流程區塊完成狀態的方式為使用此完成工作的接續,或使用 C# 和 Visual Basic 的非同步語言功能來非同步等候此完成工作。 您提供給 Task.ContinueWith 方法的委派會採用代表前項工作的 Task 物件。 在 Completion 屬性的案例中,接續的委派本身會採用完成工作。 下列範例與上一則範例很相似,不同之處在於它也會使用 ContinueWith 方法建立會列印整個資料流程作業狀態的接續工作。
// Create an ActionBlock<int> object that prints its input
// and throws ArgumentOutOfRangeException if the input
// is less than zero.
var throwIfNegative = new ActionBlock<int>(n =>
{
Console.WriteLine("n = {0}", n);
if (n < 0)
{
throw new ArgumentOutOfRangeException();
}
});
// Create a continuation task that prints the overall
// task status to the console when the block finishes.
throwIfNegative.Completion.ContinueWith(task =>
{
Console.WriteLine("The status of the completion task is '{0}'.",
task.Status);
});
// Post values to the block.
throwIfNegative.Post(0);
throwIfNegative.Post(-1);
throwIfNegative.Post(1);
throwIfNegative.Post(-2);
throwIfNegative.Complete();
// Wait for completion in a try/catch block.
try
{
throwIfNegative.Completion.Wait();
}
catch (AggregateException ae)
{
// If an unhandled exception occurs during dataflow processing, all
// exceptions are propagated through an AggregateException object.
ae.Handle(e =>
{
Console.WriteLine("Encountered {0}: {1}",
e.GetType().Name, e.Message);
return true;
});
}
/* Output:
n = 0
n = -1
The status of the completion task is 'Faulted'.
Encountered ArgumentOutOfRangeException: Specified argument was out of the range
of valid values.
*/
' Create an ActionBlock<int> object that prints its input
' and throws ArgumentOutOfRangeException if the input
' is less than zero.
Dim throwIfNegative = New ActionBlock(Of Integer)(Sub(n)
Console.WriteLine("n = {0}", n)
If n < 0 Then
Throw New ArgumentOutOfRangeException()
End If
End Sub)
' Create a continuation task that prints the overall
' task status to the console when the block finishes.
throwIfNegative.Completion.ContinueWith(Sub(task) Console.WriteLine("The status of the completion task is '{0}'.", task.Status))
' Post values to the block.
throwIfNegative.Post(0)
throwIfNegative.Post(-1)
throwIfNegative.Post(1)
throwIfNegative.Post(-2)
throwIfNegative.Complete()
' Wait for completion in a try/catch block.
Try
throwIfNegative.Completion.Wait()
Catch ae As AggregateException
' If an unhandled exception occurs during dataflow processing, all
' exceptions are propagated through an AggregateException object.
ae.Handle(Function(e)
Console.WriteLine("Encountered {0}: {1}", e.GetType().Name, e.Message)
Return True
End Function)
End Try
' Output:
' n = 0
' n = -1
' The status of the completion task is 'Faulted'.
' Encountered ArgumentOutOfRangeException: Specified argument was out of the range
' of valid values.
'
您也可以使用在接續工作主體中的屬性 (例如 IsCanceled),判斷資料流程區塊完成狀態中的其他資訊。 如需接續工作及其與取消跟錯誤處理之關聯的詳細資訊,請參閱使用接續工作鏈結工作、工作取消和例外狀況處理。
預先定義的資料流程區塊類型
TPL 資料流程程式庫提供幾種預先定義的資料流程區塊類型。 這些類型分為三類:「緩衝區塊」、「執行區塊」和「群組區塊」。 下列章節描述組成這些類別的區塊類型。
緩衝區塊
緩衝區塊保存供資料消費者使用的資料。 TPL 資料流程程式庫提供三個緩衝區塊類型:System.Threading.Tasks.Dataflow.BufferBlock<T>、System.Threading.Tasks.Dataflow.BroadcastBlock<T> 和 System.Threading.Tasks.Dataflow.WriteOnceBlock<T>。
BufferBlock<T>
BufferBlock<T> 類別代表一般用途的非同步傳訊結構。 這個類別會儲存可由多個來源寫入或由多個目標讀取之訊息的先進先出 (FIFO) 佇列。 當目標從 BufferBlock<T> 物件接收到訊息時,就會從訊息佇列中移除該訊息。 因此,雖然 BufferBlock<T> 物件可以具有多個目標,只有一個目標會接收到每則訊息。 當您想要將多則訊息傳遞給其他元件,而且該元件必須接收每則訊息時,BufferBlock<T> 類別就很有用。
下列基本範例會張貼數個 Int32 值至 BufferBlock<T> 物件,接著從該物件讀取這些值。
// Create a BufferBlock<int> object.
var bufferBlock = new BufferBlock<int>();
// Post several messages to the block.
for (int i = 0; i < 3; i++)
{
bufferBlock.Post(i);
}
// Receive the messages back from the block.
for (int i = 0; i < 3; i++)
{
Console.WriteLine(bufferBlock.Receive());
}
/* Output:
0
1
2
*/
' Create a BufferBlock<int> object.
Dim bufferBlock = New BufferBlock(Of Integer)()
' Post several messages to the block.
For i As Integer = 0 To 2
bufferBlock.Post(i)
Next i
' Receive the messages back from the block.
For i As Integer = 0 To 2
Console.WriteLine(bufferBlock.Receive())
Next i
' Output:
' 0
' 1
' 2
'
如需示範如何撰寫訊息到 BufferBlock<T> 物件,並從其中讀取訊息的完整範例,請參閱如何:寫入訊息至資料流程區塊及讀取資料流程區塊中的訊息。
BroadcastBlock<T>
當您需要將多則訊息傳遞給其他元件,但是該元件只需要最新的值時,BroadcastBlock<T> 類別就很有用。 當您想要將訊息廣播至多個元件時,這個類別也很有用。
下列基本範例會將 Double 值傳遞至 BroadcastBlock<T> 物件,然後從該物件讀取該值數次。 因為在已讀取值之後並不會從 BroadcastBlock<T> 物件中移除這些值,所以每次可用此相同的值。
// Create a BroadcastBlock<double> object.
var broadcastBlock = new BroadcastBlock<double>(null);
// Post a message to the block.
broadcastBlock.Post(Math.PI);
// Receive the messages back from the block several times.
for (int i = 0; i < 3; i++)
{
Console.WriteLine(broadcastBlock.Receive());
}
/* Output:
3.14159265358979
3.14159265358979
3.14159265358979
*/
' Create a BroadcastBlock<double> object.
Dim broadcastBlock = New BroadcastBlock(Of Double)(Nothing)
' Post a message to the block.
broadcastBlock.Post(Math.PI)
' Receive the messages back from the block several times.
For i As Integer = 0 To 2
Console.WriteLine(broadcastBlock.Receive())
Next i
' Output:
' 3.14159265358979
' 3.14159265358979
' 3.14159265358979
'
如需示範如何使用 BroadcastBlock<T> 來將訊息廣播到多個目標區塊的完整範例,請參閱如何:在資料流程區塊中指定工作排程器。
WriteOnceBlock<T>
WriteOnceBlock<T> 類別類似於 BroadcastBlock<T> 類別,但是 WriteOnceBlock<T> 物件只能被寫入一次。 您可以將 WriteOnceBlock<T> 視為類似 C# readonly (在 Visual Basic 中為 ReadOnly) 關鍵字,不過當 WriteOnceBlock<T> 物件接收到值 (而非建構) 時,它就會變成不可變。 與 BroadcastBlock<T> 類別相同的是,當目標從 WriteOnceBlock<T> 物件收到訊息時,並不會從此物件中移除該訊息。 因此,多個目標會接收此訊息的複本。 當您只想要散佈眾多訊息中的第一個時,WriteOnceBlock<T> 類別會很有用。
下列基本範例傳遞多個 String 值至 WriteOnceBlock<T> 物件,然後從該物件讀取值。 由於 WriteOnceBlock<T> 物件只能被寫入一次,所以 WriteOnceBlock<T> 物件接收到訊息之後,就會捨棄後續訊息。
// Create a WriteOnceBlock<string> object.
var writeOnceBlock = new WriteOnceBlock<string>(null);
// Post several messages to the block in parallel. The first
// message to be received is written to the block.
// Subsequent messages are discarded.
Parallel.Invoke(
() => writeOnceBlock.Post("Message 1"),
() => writeOnceBlock.Post("Message 2"),
() => writeOnceBlock.Post("Message 3"));
// Receive the message from the block.
Console.WriteLine(writeOnceBlock.Receive());
/* Sample output:
Message 2
*/
' Create a WriteOnceBlock<string> object.
Dim writeOnceBlock = New WriteOnceBlock(Of String)(Nothing)
' Post several messages to the block in parallel. The first
' message to be received is written to the block.
' Subsequent messages are discarded.
Parallel.Invoke(Function() writeOnceBlock.Post("Message 1"), Function() writeOnceBlock.Post("Message 2"), Function() writeOnceBlock.Post("Message 3"))
' Receive the message from the block.
Console.WriteLine(writeOnceBlock.Receive())
' Sample output:
' Message 2
'
如需示範如何使用 WriteOnceBlock<T> 接收第一個結束作業之值的完整範例,請參閱如何:取消連結資料流程區塊。
執行區塊
執行區塊會為已接受資料的每個部分呼叫使用者提供的委派。 TPL 資料流程程式庫提供三個執行區塊類型:ActionBlock<TInput>、System.Threading.Tasks.Dataflow.TransformBlock<TInput,TOutput> 和 System.Threading.Tasks.Dataflow.TransformManyBlock<TInput,TOutput>。
ActionBlock<T>
ActionBlock<TInput> 類別是在接收到資料時呼叫委派的目標區塊。 可將 ActionBlock<TInput> 物件視為在資料可用時會非同步執行的委派。 您提供給 ActionBlock<TInput> 物件的委派可以是 Action<T> 類型或 System.Func<TInput, Task>
類型。 當您搭配 Action<T> 使用 ActionBlock<TInput> 物件時,會將每個輸入項目的處理在委派傳回時視為完成。 當您搭配 System.Func<TInput, Task>
使用 ActionBlock<TInput> 物件時,只有在傳回的 Task 物件已完成時,才會將每個輸入項目的處理視為已完成。 使用這兩種機制,您可以使用 ActionBlock<TInput> 為每個輸入項目作同步與非同步處理。
下列基本範例會張貼多個 Int32 值到 ActionBlock<TInput> 物件。 ActionBlock<TInput> 物件會列印這些值到主控台。 這個範例接著會設定此區塊為完成狀態,並等候所有資料流程工作完成。
// Create an ActionBlock<int> object that prints values
// to the console.
var actionBlock = new ActionBlock<int>(n => Console.WriteLine(n));
// Post several messages to the block.
for (int i = 0; i < 3; i++)
{
actionBlock.Post(i * 10);
}
// Set the block to the completed state and wait for all
// tasks to finish.
actionBlock.Complete();
actionBlock.Completion.Wait();
/* Output:
0
10
20
*/
' Create an ActionBlock<int> object that prints values
' to the console.
Dim actionBlock = New ActionBlock(Of Integer)(Function(n) WriteLine(n))
' Post several messages to the block.
For i As Integer = 0 To 2
actionBlock.Post(i * 10)
Next i
' Set the block to the completed state and wait for all
' tasks to finish.
actionBlock.Complete()
actionBlock.Completion.Wait()
' Output:
' 0
' 10
' 20
'
如需示範如何使用具有 ActionBlock<TInput> 類別之委派的完整範例,請參閱如何:在資料流程區塊收到資料時執行動作。
TransformBlock<TInput, TOutput>
TransformBlock<TInput,TOutput> 類別類似於 ActionBlock<TInput> 類別,不同處在於它可同時作為來源和目標。 您傳遞給 TransformBlock<TInput,TOutput> 物件的委派會傳回類型 TOutput
的值。 您提供給 TransformBlock<TInput,TOutput> 物件的委派可以是類型 System.Func<TInput, TOutput>
或類型 System.Func<TInput, Task<TOutput>>
。 當您搭配 System.Func<TInput, TOutput>
使用 TransformBlock<TInput,TOutput> 物件時,會將每個輸入項目的處理在委派傳回時視為完成。 當您搭配 System.Func<TInput, Task<TOutput>>
使用 TransformBlock<TInput,TOutput> 物件時,只有在傳回的 Task<TResult> 物件已完成時,才會將每個輸入項目的處理視為已完成。 如同 ActionBlock<TInput>,使用這兩種機制,您就可以使用 TransformBlock<TInput,TOutput> 為每個輸入項目作同步與非同步處理。
下列基本範例會建立 TransformBlock<TInput,TOutput> 物件,該物件會計算其輸入的平方根。 TransformBlock<TInput,TOutput> 物件會使用 Int32 值做為輸入,並產生 Double 值做為輸出。
// Create a TransformBlock<int, double> object that
// computes the square root of its input.
var transformBlock = new TransformBlock<int, double>(n => Math.Sqrt(n));
// Post several messages to the block.
transformBlock.Post(10);
transformBlock.Post(20);
transformBlock.Post(30);
// Read the output messages from the block.
for (int i = 0; i < 3; i++)
{
Console.WriteLine(transformBlock.Receive());
}
/* Output:
3.16227766016838
4.47213595499958
5.47722557505166
*/
' Create a TransformBlock<int, double> object that
' computes the square root of its input.
Dim transformBlock = New TransformBlock(Of Integer, Double)(Function(n) Math.Sqrt(n))
' Post several messages to the block.
transformBlock.Post(10)
transformBlock.Post(20)
transformBlock.Post(30)
' Read the output messages from the block.
For i As Integer = 0 To 2
Console.WriteLine(transformBlock.Receive())
Next i
' Output:
' 3.16227766016838
' 4.47213595499958
' 5.47722557505166
'
如需在於 Windows Forms 應用程式中執行影像處理的資料流程區塊網路中使用 TransformBlock<TInput,TOutput> 的完整範例,請參閱逐步解說:在 Windows Forms 應用程式中使用資料流程。
TransformManyBlock<TInput, TOutput>
TransformManyBlock<TInput,TOutput> 類別相似於 TransformBlock<TInput,TOutput> 類別,不同處在於 TransformManyBlock<TInput,TOutput> 對每個輸入值會產生零或多個輸出值,而不是只有一個。 您提供給 TransformManyBlock<TInput,TOutput> 物件的委派可以是類型 System.Func<TInput, IEnumerable<TOutput>>
或類型 System.Func<TInput, Task<IEnumerable<TOutput>>>
。 當您搭配 System.Func<TInput, IEnumerable<TOutput>>
使用 TransformManyBlock<TInput,TOutput> 物件時,會將每個輸入項目的處理在委派傳回時視為完成。 當您搭配 System.Func<TInput, Task<IEnumerable<TOutput>>>
使用 TransformManyBlock<TInput,TOutput> 物件時,只有在傳回的 System.Threading.Tasks.Task<IEnumerable<TOutput>>
物件已完成時,才會將每個輸入項目的處理視為已完成。
下列基本範例會建立 TransformManyBlock<TInput,TOutput> 物件,該物件會將字串分割成獨立字元的序列。 TransformManyBlock<TInput,TOutput> 物件會使用 String 值做為輸入,並產生 Char 值做為輸出。
// Create a TransformManyBlock<string, char> object that splits
// a string into its individual characters.
var transformManyBlock = new TransformManyBlock<string, char>(
s => s.ToCharArray());
// Post two messages to the first block.
transformManyBlock.Post("Hello");
transformManyBlock.Post("World");
// Receive all output values from the block.
for (int i = 0; i < ("Hello" + "World").Length; i++)
{
Console.WriteLine(transformManyBlock.Receive());
}
/* Output:
H
e
l
l
o
W
o
r
l
d
*/
' Create a TransformManyBlock<string, char> object that splits
' a string into its individual characters.
Dim transformManyBlock = New TransformManyBlock(Of String, Char)(Function(s) s.ToCharArray())
' Post two messages to the first block.
transformManyBlock.Post("Hello")
transformManyBlock.Post("World")
' Receive all output values from the block.
For i As Integer = 0 To ("Hello" & "World").Length - 1
Console.WriteLine(transformManyBlock.Receive())
Next i
' Output:
' H
' e
' l
' l
' o
' W
' o
' r
' l
' d
'
如需使用 TransformManyBlock<TInput,TOutput> 為資料流程管線中的每個輸入產生多組獨立輸出的完整範例,請參閱逐步解說:建立資料流程管線。
平行處理原則的程度
每個 ActionBlock<TInput>、TransformBlock<TInput,TOutput>和 TransformManyBlock<TInput,TOutput> 物件會緩衝輸入訊息,直到此區塊已準備好處理它們。 這些類別預設會按照接收到訊息的順序,一次處理一個訊息。 您也可以指定平行處理原則的刻度以啟動 ActionBlock<TInput>、TransformBlock<TInput,TOutput> 和 TransformManyBlock<TInput,TOutput> 物件同時處理多個訊息。 如需同時執行的詳細資訊,請參閱本文稍後的<指定平行處理原則的刻度>一節。 如需設定平行處理原則的刻度,讓執行資料流程區塊一次可處理一個以上訊息的範例,請參閱如何:在資料流程區塊中指定平行處理原則的刻度。
委派類型摘要
下表摘要說明您可以提供給 ActionBlock<TInput>、TransformBlock<TInput,TOutput> 和 TransformManyBlock<TInput,TOutput> 物件的委派類型。 表中也會指出委派類型是以同步或非同步方式運作。
類型 | 同步委派類型 | 非同步委派類型 |
---|---|---|
ActionBlock<TInput> | System.Action |
System.Func<TInput, Task> |
TransformBlock<TInput,TOutput> | System.Func<TInput, TOutput> |
System.Func<TInput, Task<TOutput>> |
TransformManyBlock<TInput,TOutput> | System.Func<TInput, IEnumerable<TOutput>> |
System.Func<TInput, Task<IEnumerable<TOutput>>> |
當您使用執行區塊類型時,也可以使用 Lambda 運算式。 如需示範如何使用 Lambda 運算式搭配執行區塊的範例,請參閱如何:在資料流程區塊收到資料時執行動作。
群組區塊
群組區塊合併來自一個或多個來源、以及在各種條件約束下的資料。 TPL 資料流程式庫提供三個聯結區塊類型:BatchBlock<T>、JoinBlock<T1,T2> 和 BatchedJoinBlock<T1,T2>。
BatchBlock<T>
BatchBlock<T> 類別將稱為批次的輸入資料集合併為輸出資料陣列。 在建立 BatchBlock<T> 物件時,請指定每一批次的大小。 當 BatchBlock<T> 物件接收指定的輸入項目計數時,會非同步散佈包含這些項目的陣列。 如果 BatchBlock<T> 物件設定為完成狀態,但未包含足夠構成批次的項目,則會散佈包含剩餘輸入項目的最後一個陣列。
BatchBlock<T> 類別會在窮盡或非窮盡模式下運作。 在窮盡模式 (這是預設值),BatchBlock<T> 物件接受每則提供的訊息,並在接收指定的項目計數後散佈陣列。 在非窮盡模式,BatchBlock<T> 物件延後所有傳入訊息,直到來源提供給區塊的訊息足以形成批次。 因為窮盡模式需要較少的處理額外負荷,通常其效能優於非窮盡模式。 不過,在您必須以不可部分完成的方式協調來自多個來源之消耗時,可以使用非窮盡模式。 在 BatchBlock<T> 建構函式的 dataflowBlockOptions
參數中,設定 Greedy 為 False
,來指定非窮盡模式。
下列基本範例傳遞數個 Int32 值至 BatchBlock<T> 物件,該物件會在一個批次中保存十個項目。 為了保證所有的值都會從 BatchBlock<T> 散佈,此範例會呼叫 Complete 方法。 Complete 方法會將 BatchBlock<T> 物件設定為完成狀態,因此,BatchBlock<T> 物件會散佈任何的剩餘項目做為最後的批次。
// Create a BatchBlock<int> object that holds ten
// elements per batch.
var batchBlock = new BatchBlock<int>(10);
// Post several values to the block.
for (int i = 0; i < 13; i++)
{
batchBlock.Post(i);
}
// Set the block to the completed state. This causes
// the block to propagate out any remaining
// values as a final batch.
batchBlock.Complete();
// Print the sum of both batches.
Console.WriteLine("The sum of the elements in batch 1 is {0}.",
batchBlock.Receive().Sum());
Console.WriteLine("The sum of the elements in batch 2 is {0}.",
batchBlock.Receive().Sum());
/* Output:
The sum of the elements in batch 1 is 45.
The sum of the elements in batch 2 is 33.
*/
' Create a BatchBlock<int> object that holds ten
' elements per batch.
Dim batchBlock = New BatchBlock(Of Integer)(10)
' Post several values to the block.
For i As Integer = 0 To 12
batchBlock.Post(i)
Next i
' Set the block to the completed state. This causes
' the block to propagate out any remaining
' values as a final batch.
batchBlock.Complete()
' Print the sum of both batches.
Console.WriteLine("The sum of the elements in batch 1 is {0}.", batchBlock.Receive().Sum())
Console.WriteLine("The sum of the elements in batch 2 is {0}.", batchBlock.Receive().Sum())
' Output:
' The sum of the elements in batch 1 is 45.
' The sum of the elements in batch 2 is 33.
'
如需使用 BatchBlock<T> 改善資料庫插入作業效率的完整範例,請參閱逐步解說:使用 BatchBlock 和 BatchedJoinBlock 以改善效率。
JoinBlock<T1, T2, ...>
JoinBlock<T1,T2> 和 JoinBlock<T1,T2,T3> 類別會收集輸入項目,並散佈包含這些項目的 System.Tuple<T1,T2> 或 System.Tuple<T1,T2,T3> 物件。 JoinBlock<T1,T2> 和 JoinBlock<T1,T2,T3> 類別不會繼承自 ITargetBlock<TInput>。 相反地,它們提供了實作 ITargetBlock<TInput> 的屬性:Target1、Target2 和 Target3。
就像是 BatchBlock<T>、JoinBlock<T1,T2> 和 JoinBlock<T1,T2,T3>,在窮盡或非窮盡模式下操作。 在窮盡模式 (這是預設值),JoinBlock<T1,T2> 或 JoinBlock<T1,T2,T3> 物件會接受每則提供給它的訊息,並在其目標接收到至少一個訊息之後散佈 Tuple。 在非窮盡模式,JoinBlock<T1,T2> 或 JoinBlock<T1,T2,T3> 物件延後所有傳入訊息,直到建立 Tuple 所需的資料已提供至所有目標。 此時,該區塊會使用兩階段認可通訊協定,從來源以不可分割方式擷取所有必要的項目。 這項延遲使得其他實體可以同時使用資料,讓整個系統繼續進行。
下列基本範例示範 JoinBlock<T1,T2,T3> 物件要求多個資料來計算一個值的案例。 這個範例會建立需要兩個 Int32 值和一個 Char 值來執行算術運算的 JoinBlock<T1,T2,T3> 物件。
// Create a JoinBlock<int, int, char> object that requires
// two numbers and an operator.
var joinBlock = new JoinBlock<int, int, char>();
// Post two values to each target of the join.
joinBlock.Target1.Post(3);
joinBlock.Target1.Post(6);
joinBlock.Target2.Post(5);
joinBlock.Target2.Post(4);
joinBlock.Target3.Post('+');
joinBlock.Target3.Post('-');
// Receive each group of values and apply the operator part
// to the number parts.
for (int i = 0; i < 2; i++)
{
var data = joinBlock.Receive();
switch (data.Item3)
{
case '+':
Console.WriteLine("{0} + {1} = {2}",
data.Item1, data.Item2, data.Item1 + data.Item2);
break;
case '-':
Console.WriteLine("{0} - {1} = {2}",
data.Item1, data.Item2, data.Item1 - data.Item2);
break;
default:
Console.WriteLine("Unknown operator '{0}'.", data.Item3);
break;
}
}
/* Output:
3 + 5 = 8
6 - 4 = 2
*/
' Create a JoinBlock<int, int, char> object that requires
' two numbers and an operator.
Dim joinBlock = New JoinBlock(Of Integer, Integer, Char)()
' Post two values to each target of the join.
joinBlock.Target1.Post(3)
joinBlock.Target1.Post(6)
joinBlock.Target2.Post(5)
joinBlock.Target2.Post(4)
joinBlock.Target3.Post("+"c)
joinBlock.Target3.Post("-"c)
' Receive each group of values and apply the operator part
' to the number parts.
For i As Integer = 0 To 1
Dim data = joinBlock.Receive()
Select Case data.Item3
Case "+"c
Console.WriteLine("{0} + {1} = {2}", data.Item1, data.Item2, data.Item1 + data.Item2)
Case "-"c
Console.WriteLine("{0} - {1} = {2}", data.Item1, data.Item2, data.Item1 - data.Item2)
Case Else
Console.WriteLine("Unknown operator '{0}'.", data.Item3)
End Select
Next i
' Output:
' 3 + 5 = 8
' 6 - 4 = 2
'
如需在非窮盡模式中使用 JoinBlock<T1,T2> 物件以合作方式共用資源的完整範例,請參閱如何:使用 JoinBlock 從多個來源讀取資料。
BatchedJoinBlock<T1, T2, ...>
BatchedJoinBlock<T1,T2> 和 BatchedJoinBlock<T1,T2,T3> 類別會收集輸入項目的批次,並散佈包含這些項目的 System.Tuple(IList(T1), IList(T2))
或 System.Tuple(IList(T1), IList(T2), IList(T3))
物件。 請將 BatchedJoinBlock<T1,T2> 視為 BatchBlock<T> 和 JoinBlock<T1,T2> 的組合。 當您建立 BatchedJoinBlock<T1,T2> 物件時,請指定每一批次的大小。 BatchedJoinBlock<T1,T2> 也提供會實作 ITargetBlock<TInput> 的屬性:Target1 和 Target2。 當收到來自所有目標的指定輸入項目計數時,BatchedJoinBlock<T1,T2> 物件會非同步散佈包含這些項目的 System.Tuple(IList(T1), IList(T2))
物件。
下列基本範例建立會保存結果的 BatchedJoinBlock<T1,T2> 物件、Int32 值,以及為 Exception 物件的錯誤。 這個範例執行多個作業,並將結果寫入 BatchedJoinBlock<T1,T2> 物件的 Target1 屬性,將錯誤寫入 Target2 屬性。 由於事先不知道成功和失敗的作業計數,IList<T> 物件可讓每個目標接收零或多個值。
// For demonstration, create a Func<int, int> that
// returns its argument, or throws ArgumentOutOfRangeException
// if the argument is less than zero.
Func<int, int> DoWork = n =>
{
if (n < 0)
throw new ArgumentOutOfRangeException();
return n;
};
// Create a BatchedJoinBlock<int, Exception> object that holds
// seven elements per batch.
var batchedJoinBlock = new BatchedJoinBlock<int, Exception>(7);
// Post several items to the block.
foreach (int i in new int[] { 5, 6, -7, -22, 13, 55, 0 })
{
try
{
// Post the result of the worker to the
// first target of the block.
batchedJoinBlock.Target1.Post(DoWork(i));
}
catch (ArgumentOutOfRangeException e)
{
// If an error occurred, post the Exception to the
// second target of the block.
batchedJoinBlock.Target2.Post(e);
}
}
// Read the results from the block.
var results = batchedJoinBlock.Receive();
// Print the results to the console.
// Print the results.
foreach (int n in results.Item1)
{
Console.WriteLine(n);
}
// Print failures.
foreach (Exception e in results.Item2)
{
Console.WriteLine(e.Message);
}
/* Output:
5
6
13
55
0
Specified argument was out of the range of valid values.
Specified argument was out of the range of valid values.
*/
' For demonstration, create a Func<int, int> that
' returns its argument, or throws ArgumentOutOfRangeException
' if the argument is less than zero.
Dim DoWork As Func(Of Integer, Integer) = Function(n)
If n < 0 Then
Throw New ArgumentOutOfRangeException()
End If
Return n
End Function
' Create a BatchedJoinBlock<int, Exception> object that holds
' seven elements per batch.
Dim batchedJoinBlock = New BatchedJoinBlock(Of Integer, Exception)(7)
' Post several items to the block.
For Each i As Integer In New Integer() {5, 6, -7, -22, 13, 55, 0}
Try
' Post the result of the worker to the
' first target of the block.
batchedJoinBlock.Target1.Post(DoWork(i))
Catch e As ArgumentOutOfRangeException
' If an error occurred, post the Exception to the
' second target of the block.
batchedJoinBlock.Target2.Post(e)
End Try
Next i
' Read the results from the block.
Dim results = batchedJoinBlock.Receive()
' Print the results to the console.
' Print the results.
For Each n As Integer In results.Item1
Console.WriteLine(n)
Next n
' Print failures.
For Each e As Exception In results.Item2
Console.WriteLine(e.Message)
Next e
' Output:
' 5
' 6
' 13
' 55
' 0
' Specified argument was out of the range of valid values.
' Specified argument was out of the range of valid values.
'
如需使用 BatchedJoinBlock<T1,T2> 來擷取程式從資料庫讀取時所發生的結果和任何例外狀況的完整範例,請參閱逐步解說:使用 BatchBlock 和 BatchedJoinBlock 以改善效率。
設定資料流程區塊行為
您可以對資料流程區塊類型建構函式提供 System.Threading.Tasks.Dataflow.DataflowBlockOptions 物件來啟用其他選項。 這些選項可控制行為,例如會管理基礎工作和平行處理原則刻度的排程器。 DataflowBlockOptions 也衍生出會指定某些資料流程區塊類型特定行為的類型。 下表摘要說明與各資料流程區塊類型相關聯的選項類型。
下列章節提供可用於 System.Threading.Tasks.Dataflow.DataflowBlockOptions、System.Threading.Tasks.Dataflow.ExecutionDataflowBlockOptions 和 System.Threading.Tasks.Dataflow.GroupingDataflowBlockOptions 類別中重要的資料流程選項種類之其他資訊。
指定工作排程器
每個預先定義的資料流程區塊使用 TPL 工作排程機制來執行活動,例如當資料可用時散佈資料至目標、接收來自來源的資料和執行使用者定義的委派。 TaskScheduler 是一種抽象類別,代表在執行緒上將工作排入佇列的工作排程器。 預設工作排程器 Default 使用 ThreadPool 類別將工作排入佇列並執行。 您可以在建構資料流程區塊物件時設定 TaskScheduler 屬性,來覆寫預設工作排程器。
在同一個工作排程器管理多個資料流程區塊時,它可以跨區塊強制執行原則。 例如,如果多個資料流程區塊分別設定為以相同 ConcurrentExclusiveSchedulerPair 物件的獨佔排程器為目標,則會將所有跨區塊執行的的工作序列化。 同樣地,如果這些區塊設定為以相同 ConcurrentExclusiveSchedulerPair 物件的並行排程器為目標,且該排程器已設定為具有最大並行層級,則所有來自這些區塊的工作都受限於並行作業的數目。 如需使用 ConcurrentExclusiveSchedulerPair 類別來使讀取作業以平行方式發生,但使寫入作業僅會針對所有其他作業發生的範例,請參閱如何:在資料流程區塊中指定工作排程器。 如需 TPL 中工作排程器的詳細資訊,請參閱 TaskScheduler 類別主題。
指定平行處理原則的刻度
根據預設,TPL 資料流程程式庫所提供的三個執行區塊類型 ActionBlock<TInput>、TransformBlock<TInput,TOutput> 和 TransformManyBlock<TInput,TOutput>,一次處理一個訊息。 這些資料流程區塊類型也都會按照接收到訊息的順序處理訊息。 在建構資料流程區塊物件時,要讓這些資料流程區塊同時處理訊息,請設定 ExecutionDataflowBlockOptions.MaxDegreeOfParallelism 屬性。
MaxDegreeOfParallelism 的預設值為 1,以保證該資料流程區塊一次處理一個訊息。 設定此屬性為大於 1 的值可讓資料流程區塊同時處理多個訊息。 設定此屬性為 DataflowBlockOptions.Unbounded 可啟用基本的工作排程器來管理最大並行刻度。
重要
當您指定大於 1 的最大平行處理原則刻度時,將會同時處理多個訊息,因此訊息可能不會依照接收到的順序處理。 不過,訊息從區塊輸出的順序和收到的順序一樣。
因為 MaxDegreeOfParallelism 屬性表示平行處理原則的最大刻度,所以資料流程區塊可能會以比您所指定刻度更小的平行處理原則來執行。 資料流程區塊可能使用較低刻度的平行處理以符合其功能需求,或者是因為缺乏可用的系統資源。 資料流程區塊絕不選擇高於您所指定的平行處理。
MaxDegreeOfParallelism 屬性的值對每個資料流程區塊物件是獨佔的。 例如,如果四個資料流程區塊物件每一個都為平行處理原則的最大刻度指定為 1,則全部四個資料流程區塊物件都可以平行執行。
如需設定平行處理原則的最大刻度,讓長時間作業平行處理的範例,請參閱如何:在資料流程區塊中指定平行處理原則刻度。
指定每項工作的訊息數量
預先定義的資料流程區塊類型使用工作以處理多個輸入項目。 這有助於減少被要求處理資料的工作物件數目,使得應用程式更有效率地執行。 不過,當來自一組工作資料流程區塊的工作正在處理資料時,來自其他資料流程區塊的工作可能需要將訊息加入佇列來等候處理時間。 若要提升資料流程中工作的公平性,請設定 MaxMessagesPerTask 屬性。 當 MaxMessagesPerTask 設定為 DataflowBlockOptions.Unbounded (預設) 時,由資料流程區塊所使用的工作會盡可能多地處理訊息。 在 MaxMessagesPerTask 設定為除了 Unbounded 以外的值時,即為資料流程區塊對每個 Task 物件至多處理的訊息數量。 雖然設定 MaxMessagesPerTask 屬性可能會在工作之間提升公平性,但它可能造成系統建立更多超出所需的工作,反而可能會降低效能。
啟用取消
TPL 提供一種讓工作以合作方式協調取消的機制。 若要讓資料流程區塊參與此取消機制,請設定 CancellationToken 屬性。 當此 CancellationToken 物件設定為已取消狀態時,所有監視此語彙基元的資料流程區塊會結束執行其目前項目,但不開始處理後續項目。 這些資料流程區塊也會清除任何緩衝訊息,釋放連結給任何來源區塊和目標區塊,並轉換為取消狀態。 除非在處理期間發生例外狀況,不然 Completion 屬性將透過轉換到已取消的狀態,將 Status 屬性設定為 Canceled。 在此情況下,Status 會設定為 Faulted。
如需示範如何在 Windows Forms 應用程式中使用取消的範例,請參閱如何:取消資料流程區塊。 如需 TPL 中取消的詳細資訊,請參閱工作取消。
指定窮盡與非窮盡的行為
許多群組資料流程區塊類型可以在「窮盡」或「非窮盡」模式中運作。 預先定義的資料流程區塊類型預設會在窮盡模式下運作。
對於聯結區塊類型 (例如 JoinBlock<T1,T2>),窮盡模式表示即使與其相聯結的對應資料尚未可用,區塊會立即接受資料。 非窮盡模式則表示區塊會延後處理所有傳入訊息,直到其中之一在其每個目標上可用於完成聯結。 如果任何延後的訊息皆不再可用,則聯結區塊會釋出所有延後的訊息,並重新啟動此程序。 對於 BatchBlock<T> 類別,窮盡和非窮盡的行為類似,但是在非窮盡模式下,BatchBlock<T> 物件將所有傳入訊息延後,直到來自不同來源的訊息足夠可用,以完成批次。
若要為資料流程區塊指定非窮盡模式,請將 Greedy 設為 False
。 如需示範如何使用非窮盡模式,讓多個聯結區塊更有效率共用資料來源的範例,請參閱如何:使用 JoinBlock 從多個來源讀取資料。
自訂資料流程區塊
雖然 TPL 資料流程程式庫提供許多預先定義的區塊類型,但您可以建立會執行自訂行為的其他區塊類型。 直接實作 ISourceBlock<TOutput> 或 ITargetBlock<TInput> 介面,或是使用 Encapsulate 方法來建立封裝現有區塊類型行為的複雜區塊。 如需示範如何實作自訂資料流程區塊功能的範例,請參閱逐步解說:建立自訂資料流程區塊類型。
[相關主題]
標題 | 描述 |
---|---|
操作說明:對資料流程區塊寫入訊息和讀取訊息 | 示範如何寫入訊息至 BufferBlock<T> 物件及讀取該物件中的訊息。 |
操作說明:實作產生者-取用者資料流程模式 | 描述如何使用此資料流程模型以實作生產者-消費者模式,其中生產者傳送訊息至資料流程區塊,而消費者從該區塊讀取訊息。 |
如何:在資料流程區塊收到資料時執行動作 | 說明如何提供委派給執行資料流程區塊類型 ActionBlock<TInput>、TransformBlock<TInput,TOutput> 和 TransformManyBlock<TInput,TOutput>。 |
逐步解說:建立資料流程管線 | 描述如何建立可以從網路下載文字並對該文字執行作業的資料流程管線。 |
如何:取消連結資料流程區塊 | 示範如何使用 LinkTo 方法,來在來源為目標提供訊息之後,將目標區塊與其來源取消連結。 |
逐步解說:在 Windows Forms 應用程式中使用資料流程 | 示範如何建立資料流程區塊網路,其可以在 Windows Form 應用程式中執行影像處理。 |
操作說明:取消資料流程區塊 | 示範如何在 Windows Form 應用程式中使用取消。 |
操作說明:使用 JoinBlock 從多個來源讀取資料 | 說明如何在資料可取自多重來源時使用 JoinBlock<T1,T2> 類別執行作業,以及如何使用非窮盡模式使得多重聯結區塊可以更有效率地共用資料來源。 |
如何:在資料流程區塊中指定平行處理原則刻度 | 描述如何設定 MaxDegreeOfParallelism 屬性使執行資料流程區塊可以同時處理一個以上的訊息。 |
操作說明:在資料流程區塊中指定工作排程器 | 示範當您在應用程式中使用資料流程時,要如何與特定工作排程器建立關聯。 |
逐步解說:使用 BatchBlock 和 BatchedJoinBlock 以改善效率 | 說明如何使用 BatchBlock<T> 類別來改善資料庫插入作業的效率,以及說明如何使用 BatchedJoinBlock<T1,T2> 類別在程式讀取資料庫時擷取結果和發生的任何例外狀況。 |
逐步解說:建立自訂資料流程區塊類型 | 示範建立會實作自訂行為的資料流程區塊類型之兩種方式。 |
工作平行程式庫 (TPL) | 介紹 TPL,這是一種在 .NET Framework 應用程式中簡化平行和並行程式設計的程式庫。 |