[C#.NET][TPL] 利用 TaskFactory 完成多項任務

[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);
}

 

執行畫面:

SNAGHTMLecc1def

 


範例下載:

 

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

Image result for microsoft+mvp+logo