[C#.NET][TPL] 利用 TaskFactory 完成多項任務
當有多個任務要執,而這些任務彼此之間沒有相依順序,我們可以使用 Task.Factory.ContinueWhenAll 來等待任務,這個例子會比之前的文章還要長一些,主要就是用多個任務讀取多個檔案
使用上篇介紹的 http://www.dotblogs.com.tw/yc421206/archive/2013/08/06/113555.aspx,讀檔非同步模型
內文章節:
接下來就來看點範例
private Task<string> ReadFileAsync(string fileName, CancellationToken cancellationToken) { FileInfo info = new FileInfo(fileName); if (!info.Exists) { return null; } var stream = new FileStream(fileName, FileMode.Open, FileAccess.Read); var buffer = new byte[info.Length]; var mainTask = Task<int>.Factory.FromAsync(stream.BeginRead, stream.EndRead, buffer, 0, buffer.Length, null); var subTask = mainTask.ContinueWith(task => { var length = 0; if (task.Status == TaskStatus.RanToCompletion) { length = task.Result; } return length == 0 ? null : Encoding.UTF8.GetString(buffer); }, cancellationToken); return subTask; }
建立 fileTasks 集合,並指派每一個任務讀檔
TaskScheduler 處理 UI 通知,詳細用法參考 http://www.dotblogs.com.tw/yc421206/archive/2013/08/07/113652.aspx
用Task.Factory.ContinueWhenAll 等待所有任務
private void ReadAllFileAsync(string[] fileNames, CancellationToken cancellationToken, TaskScheduler uiScheduler) { var fileTasks = new List<Task<string>>(fileNames.Length); var mainTask = Task.Factory.StartNew(() => { StringBuilder sb = new StringBuilder(); foreach (var name in fileNames) { if (cancellationToken.IsCancellationRequested) cancellationToken.ThrowIfCancellationRequested(); var task = ReadFileAsync(name, cancellationToken); fileTasks.Add(task); if (task == null) continue; task.ContinueWith(t => { var content = ""; if (t.Status == TaskStatus.RanToCompletion) { content = task.Result; } //更新UI this.progressBar1.Value++; this.listBox1.Items.Add(content); this.m_SynchronizationContext.Post(_ => { }, null); }, cancellationToken, TaskContinuationOptions.None, uiScheduler); SpinWait.SpinUntil(() => { if (this.m_cts.Token.IsCancellationRequested) this.m_cts.Token.ThrowIfCancellationRequested(); return false; }, 500); } Task.Factory.ContinueWhenAll(fileTasks.ToArray(), tasks => { foreach (Task<string> task in tasks) { if (task.Status == TaskStatus.RanToCompletion) { sb.Append(task.Result); } } this.textBox1.Text = sb.ToString(); }, cancellationToken, TaskContinuationOptions.None, uiScheduler); }, cancellationToken); mainTask.ContinueWith(task => { try { var status = string.Format("任務完成,完成狀態為:\rIsCanceled={0}\rIsCompleted={1}\rIsFaulted={2}", task.IsCanceled, task.IsCompleted, task.IsFaulted); MessageBox.Show(status); } catch (AggregateException ex) { MessageBox.Show(ex.Message); } }); }
private void button_Start_Click(object sender, EventArgs e) { this.m_cts = new CancellationTokenSource(); var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext(); string[] fileNames = new string[] { "TextFile1.txt", "TextFile2.txt", "TextFile3.txt", "TextFile4.txt", "TextFile5.txt", "TextFile6.txt", "TextFile7.txt", }; this.listBox1.Items.Clear(); this.textBox1.Clear(); this.progressBar1.Value = 0; this.progressBar1.Maximum = fileNames.Length; ReadAllFileAsync(fileNames, this.m_cts.Token, uiScheduler); }
https://dotblogsfile.blob.core.windows.net/user/yc421206/1308/20138819211317.zip
文章出處:
http://www.dotblogs.com.tw/yc421206/archive/2013/08/08/113859.aspx
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET