我一直在嘗試通過創建示例應用程序來了解TPL數據流。我一直在試圖做的一件事是從ActionBlock
更新TextBox
控件。使用TPL Dataflow的原因是在保持順序的同時執行並行異步操作。以下函數由我自己編寫,從ActionBlock更新UI控件
private TaskScheduler scheduler = null;
public Form1()
{
this.scheduler = TaskScheduler.FromCurrentSynchronizationContext();
InitializeComponent();
}
public async void btnTPLDataFlow_Click(object sender, EventArgs e)
{
Stopwatch watch = new Stopwatch();
watch.Start();
txtOutput.Clear();
ExecutionDataflowBlockOptions execOptions = new ExecutionDataflowBlockOptions();
execOptions.MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded;
execOptions.TaskScheduler = scheduler;
ActionBlock<int> actionBlock = new ActionBlock<int>(async v =>
{
bool x = await InsertIntoDatabaseAsync(v);
if (x)
txtOutput.Text += "Value Inserted for: " + v + Environment.NewLine;
else
txtOutput.Text += "Value Failed for: " + v + Environment.NewLine;
}, execOptions);
for (int i = 1; i <= 200; i++)
{
actionBlock.Post(i);
}
actionBlock.Complete();
await actionBlock.Completion;
watch.Stop();
lblTPLDataFlow.Text = Convert.ToString(watch.ElapsedMilliseconds/1000);
}
private async Task<bool> InsertIntoDatabaseAsync(int id)
{
try
{
string connString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=D:\\TPLDatabase.accdb;Persist Security Info=False;";
using (OleDbConnection conn = new OleDbConnection(connString))
{
string commandText = "INSERT INTO tblRecords (ProductName, ProductDescription, IsProcessed) VALUES (@ProductName, @ProductDescription, @IsProcessed)";
await conn.OpenAsync();
using (OleDbCommand command = new OleDbCommand(commandText, conn))
{
command.CommandType = CommandType.Text;
command.Parameters.AddWithValue("@ProductName", "Product " + id);
command.Parameters.AddWithValue("@ProductDescription", "Description " + id);
command.Parameters.AddWithValue("@IsProcessed", false);
if (await command.ExecuteNonQueryAsync() > 0)
return true;
else
return false;
}
}
}
catch
{
return false;
}
}
現在上面這段代碼運行得很好。它按順序在我的示例MS Access數據庫中插入記錄,並按順序更新UI。但與此問題是,它阻止了用戶界面,這是可以理解的,因爲我正在使用將在UI線程上更新TextBox
的TaskScheduler.FromCurrentSynchronizationContext
。
我在代碼中做了一些小改動,並從ExecutionDataflowBlockOptions
中刪除了調度程序。相反,我用下面的代碼更新UI,
txtOutput.Invoke(new MethodInvoker(delegate
{
if (x)
txtOutput.Text += "Value Inserted for: " + v + Environment.NewLine;
else
txtOutput.Text += "Value Failed for: " + v + Environment.NewLine;
}));
現在,這個變化不會凍結UI,但被嚴重擾亂,在文本框中顯示的值的數據庫和訂單值的順序。新順序是這樣的,
ID ProductName ProductDescription IsProcessed
6847 Product 6 Description 6 False
6848 Product 7 Description 7 False
6849 Product 8 Description 8 False
6850 Product 10 Description 10 False
6851 Product 11 Description 11 False
6852 Product 12 Description 12 False
6853 Product 9 Description 9 False
6854 Product 13 Description 13 False
6855 Product 14 Description 14 False
現在什麼都可以更新我的方案的UI,並且還保持秩序的最佳途徑。
大。謝謝你回答並建議處理這種情況的方法。因爲我對此很陌生,所以只是好奇,TransformBlock比ActionBlock有什麼好處。 (我認爲這兩個參數的意思是一個用於輸入,另一個用於輸出,對嗎?我還需要等待TransformBlock或ActionBlock的完成嗎?最重要的是,如果任何一個塊發生異常,並且如果我拋出那麼所有的塊都會被異常終止? –
好處是將工作分成兩塊,並且由於你需要鏈接它們,你首先需要成爲'TrasnformBlock'。 – i3arnon
是的,第一種類型是輸入,第二種是輸入是輸出 – i3arnon