文章出處

接上文 多線程編程學習筆記——任務并行庫(一)

接上文 多線程編程學習筆記——任務并行庫(二)

 接上文 多線程編程學習筆記——任務并行庫(三)

 

八、   并行運行任務

        本示例學習如何同時運行多個任務,并且當任務全部完成或其中一個完成時,如何高效的得到通知。

1.示例代碼

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ThreadPoolDemo
{  

    class Program
    {

        static void Main(string[] args)
        {
            Console.WriteLine(" 處理并行Task。。。。。");       

                var task1 = new Task<int>(() => RunTask("任務 1", 3));     

        

                var task2 = new Task<int>(() => RunTask("任務 2", 2));
            var whenTaskAll = Task.WhenAll(task1, task2);

             whenTaskAll.ContinueWith(t => Console.WriteLine(" ——task1 結果值={0}---task2 結果值={1}",t.Result[0],t.Result[1]),
TaskContinuationOptions.OnlyOnRanToCompletion); task1.Start(); task2.Start(); Thread.Sleep(
5000); Console.WriteLine(" ——————————————————————"); var tasks = new List<Task<int>>(); for (int i = 3; i < 10; i++) { int cnt = i; var task = new Task<int>(() => RunTask(string.Format("任務 {0}",cnt), cnt)); tasks.Add(task); task.Start(); } while(tasks.Count>0) { var completedTask = Task.WhenAny(tasks).Result; tasks.Remove(completedTask); Console.WriteLine(" ——一個task 完成任務—結果值={0}", completedTask.Result); } Thread.Sleep(7000); Console.Read(); } private static int RunTask(string name,int seconds) { Console.WriteLine("Task {0} 運行在線程={1}中,是否在線程池 :{2}",name,
Thread.CurrentThread.ManagedThreadId,Thread.CurrentThread.IsThreadPoolThread); Thread.Sleep(TimeSpan.FromSeconds(seconds));
return 20 * seconds; } } }

2。程序運行結果。如下圖。

 

       當程序啟動時,創建了兩個任務(task1,task2),然后用task.whenall方法創建了第三個任務,這個任務會在所有任務完成之后運行。這個任務的結果提供了一個數組,第一個元素是第一個任務的結果,第二個元素是第二個任務的結果,以此類推。

        然后我們創建了一個任務列表,列表中有七個任務,然后使用task.whenany方法,等這一系列任務中的任何一個任務完成 ,就從列表中移除,并繼續等待其他任務完成,直到列表為空。

九、   使用taskScheduler配置任務的執行

      我們學習任務調度程序,通過異步代碼與UI進行交互。所以本示例是創建Windows應用程序。

      taskScheduler是負責如何執行任務,默認情況下是把task放入線程池中的工作線程中。

 1.在visual studio 中創建一個windowsForm個界面,名稱為FormTPL 這個界面中有同步,異步兩個按鈕。

 2.程序界面如下圖。

 3.代碼如下。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms; 

namespace ThreadTPLDemo
{
    public partial class FormTPL : Form
    {

        public FormTPL()
        {
            InitializeComponent();

        } 

        private void buttonSync_Click(object sender, EventArgs e)
        {

            try
            {
                string result = RunTask().Result;
                textBoxMsg.Text = result;

            }
            catch (Exception ex)

            {      
          textBoxMsg.Text = ex.Message;
            }      

        } 

        private void buttonAsync_Click(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;

            Task<string> task = RunTask();
            task.ContinueWith(t =>
            {
                textBoxMsg.Text = t.Exception.InnerException.Message;
                this.Cursor = Cursors.Arrow;
            }, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted,TaskScheduler.FromCurrentSynchronizationContext());
 
        }

        private void buttonAsyncOk_Click(object sender, EventArgs e)
        {

            this.Cursor = Cursors.WaitCursor;
            Task<string> task = RunTask(TaskScheduler.FromCurrentSynchronizationContext());
            task.ContinueWith(t =>this.Cursor=Cursors.Arrow,
            CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.FromCurrentSynchronizationContext());

        }

        private Task<string> RunTask()
        {
            return RunTask(TaskScheduler.Default);

        }
 

        private Task<string> RunTask(TaskScheduler tsched)
        {
            Task delay = Task.Delay(TimeSpan.FromSeconds(5));
            return delay.ContinueWith(t =>
            {
                string str = string.Format("Task 運行在線程={0},是否是在線程池中運行:{1}",Thread.CurrentThread.ManagedThreadId, 
Thread.CurrentThread.IsThreadPoolThread); textBoxMsg.Text
= str; return str; },tsched); } } }

 4。程序運行結果中會出現第一個問題,當點擊同步按鈕,執行程序時,整個應用 程序的用戶界面假死,無法進行其他的任務操作。如下圖。從圖中2處可以看出“異步交互”按鈕無法顯示。

 

  5.  解決同步執行界面會假死的問題,我們使用異步執行的方式解決。

  6. 第二個問題,而且當我們從線程中直接訪問UI界面中的控件時,會拋出異常。

      

   7. 當我們按第三個按鈕,然后執行代碼,程序正常運行,并得到結果。如下圖。

 

 

      最后,本人不建議使用taskScheduler來開發任務調度程序,建議使用Quartz.Net來開發任務調度程序。


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()