溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

C#多線程Task的使用

發(fā)布時間:2021-08-25 17:11:15 來源:億速云 閱讀:294 作者:chen 欄目:大數(shù)據(jù)

這篇文章主要講解了“C#多線程Task的使用”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“C#多線程Task的使用”吧!

背景

當(dāng)我們程序在執(zhí)行長時間數(shù)據(jù)處理時,如果只用主進程,會出現(xiàn)卡死或是假死等待時間長的情況,如果這個時間我們用到多線程操作,不但可以減少耗時,執(zhí)行過程中可以簡單同步UI界面,讓人看到不會有種假死的狀態(tài).

要求

我們要遍達(dá)30W數(shù)據(jù),分成6個任務(wù),每個任務(wù)處理5W數(shù)據(jù),然后同時并行的任務(wù)是3項.每個任務(wù)遍歷完成后生成一個TXT的文件.

設(shè)計思路

我們通過多個任務(wù)添加多個用戶控件的方法,然后在控件的TAG里設(shè)置為bool類型,用于判斷任務(wù)是否已經(jīng)執(zhí)行了,然后在線程操作的時候首先找到未執(zhí)行的任務(wù),然后更新TAG標(biāo)志并處理任務(wù),處理完當(dāng)前任務(wù)數(shù)據(jù)后再把數(shù)據(jù)寫入到當(dāng)前目錄下的txt文件里面,直到所有的任務(wù)都完成后結(jié)束線程.

知識點

  • 用戶控件的設(shè)計

  • 動態(tài)創(chuàng)建控件

  • 線程Task的操作

編碼

打開VS,我用的是2017,新建一個項目名稱為TaskDemo

在Form里面我們加三個控件,分別是FlowLayoutPanel ,TextBox和一個Button

C#多線程Task的使用

左邊的FlowLayoutPanel是一會兒我們自己建個用戶控件來顯示任務(wù)列表的,這個可以自適應(yīng)排列.

接下來我們在解決方案里面鼠標(biāo)右鍵選擇添加新建一個用戶控件起名為TaskCtrl

C#多線程Task的使用

C#多線程Task的使用

建好后我們在這里面增加幾個Label和一個ProgressBar

C#多線程Task的使用

在userctrl里定義三個值

        //任務(wù)號
        public int Taskno;
        //開始記錄數(shù)
        public int Startrecord;
        //結(jié)束記錄數(shù)
        public int Endrecord;

然后重新改一下構(gòu)造函數(shù)

        public TaskCtrl(int taskno, int startrecord, int endrecord)
        {
            Taskno = taskno;
            Startrecord = startrecord;
            Endrecord = endrecord;
            InitializeComponent();

            lblTaskNo.Text = "任務(wù)號:" + Taskno;
            lblRecord.Text = "任務(wù)記錄數(shù):" + (Endrecord - Startrecord);

            prgb.Minimum = Startrecord;
            prgb.Maximum = Endrecord;
            prgb.Value = Startrecord;
        }

我們再增加一個方法,用于更新顯示當(dāng)前的任務(wù)

        /// <summary>
        /// 顯示進度條和信息
        /// </summary>
        /// <param name="row"></param>
        public void ShowProgressbar(int row)
        {
            prgb.Value = row;
            lblStatus.Text = row + "/" + Endrecord;
        }

這樣用戶控件我們就完成了.下面開始寫主界面的按鈕事件

首先我們定義幾個值,像總數(shù)據(jù),每項任務(wù)的值,同時并行任務(wù)數(shù)

C#多線程Task的使用

然后我們再定義一個委托,用于線程執(zhí)行過程中可以同步UI顯示當(dāng)前狀態(tài)的

C#多線程Task的使用

接下來就是我們開始寫按鈕事件

先寫一個初始化用戶控件的方法

        /// <summary>
        /// 初始化flowlayoutpanel獲取用戶控件
        /// </summary>
        private void InitFlowLayoutPanel()
        {
            flpnl.Controls.Clear();
            //計算任務(wù)個數(shù)
            //總數(shù)除每個任務(wù)最大數(shù),如果有余數(shù)任務(wù)數(shù)+1,如果不有余數(shù)就是任務(wù)數(shù)
            int taskqty = totalrecord % taskrecord > 0 ? totalrecord / taskrecord + 1 : taskrecord / taskrecord;
            //循環(huán)自動創(chuàng)建用戶控件
            for (int i = 0; i < taskqty; i++)
            {
                //計算當(dāng)前任務(wù)的開始記錄和結(jié)束記錄
                int startrecord = i == 0 ? 1 : i * taskrecord + 1;
                int endrecord = i == 0 ? taskrecord : (i + 1) * taskrecord;

                TaskCtrl userctrl = new TaskCtrl(i, startrecord, endrecord);
                userctrl.Name = "Task" + i;
                //Tag標(biāo)志用于記錄當(dāng)前任務(wù)是否已經(jīng)完成
                userctrl.Tag = false;

                flpnl.Controls.Add(userctrl);
            }
        }

業(yè)務(wù)處理的核心代碼

       /// <summary>
        /// 線程操作
        /// </summary>
        private void TaskModify()
        {
            Task parent = new Task(() =>
            {
                var cts = new CancellationTokenSource();
                var tf = new TaskFactory(cts.Token, TaskCreationOptions.AttachedToParent,
                    TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);

                //定義數(shù)組執(zhí)行的任務(wù)
                Task[] childTasks = new Task[tasknum - 1];
                //賦值
                for (int task = 0; task < tasknum; task++)
                {
                    childTasks [task] = tf.StartNew(() =>
                    {
                        bool res = true;
                        while (res)
                        {
                            Thread.Sleep(2000);
                            //每次執(zhí)行完后得到返回值用于查詢是否還有未完成任務(wù)
                            //如果有繼續(xù)執(zhí)行,沒有就退出線程
                            res = DoTask();
                        }
                    }, cts.Token).ContinueWith(t =>
                    {
                        if (t.IsCompleted)
                        {
                            this.BeginInvoke(TextShow, "當(dāng)前線程任務(wù)都執(zhí)行完畢!!");
                        }
                        else if (t.IsCanceled)
                        {
                            this.BeginInvoke(TextShow, "當(dāng)前線程取消任務(wù)!!");
                        }
                        else if (t.IsFaulted)
                        {
                            this.BeginInvoke(TextShow, "當(dāng)前線程異常!!");
                        }
                    }, cts.Token);
                    Thread.Sleep(200);
                }
            });

            parent.Start();
        }

數(shù)據(jù)處理的相關(guān)代碼

       /// <summary>
        /// 獲取用戶控件,判斷是否已經(jīng)執(zhí)行完任務(wù)
        /// </summary>
        /// <returns></returns>
        private TaskCtrl GetUserCtrl()
        {
            TaskCtrl ctrl = null;
            foreach (Control c in flpnl.Controls)
            {
                ctrl = c as TaskCtrl;
                //判斷用戶控件是否已經(jīng)完成任務(wù)
                if (ctrl != null && !(bool) ctrl.Tag)
                {
                    return ctrl;
                }
            }
            return null;
        }

        private bool DoTask()
        {
            bool res = false;
            string str = string.Empty;
            //獲取用戶控件,如果不為空即開始任務(wù)
            TaskCtrl taskCtrl = GetUserCtrl();
            if (taskCtrl != null)
            {
                //獲取后更新用戶控件標(biāo)志
                res = true;
                taskCtrl.Tag = res;
                //定義上次顯示的行數(shù)
                int lastshow = 0;
                for (int row = taskCtrl.Startrecord; row < taskCtrl.Endrecord; row++)
                {
                    //拼接循環(huán)的字符串
                    str = str + "<record>" + row + "</record>";
                    //防止每條都更新UI造成阻塞,設(shè)置每1000條更新一次UI
                    if (row - lastshow > 1000 || row == taskCtrl.Endrecord)
                    {
                        this.BeginInvoke(TaskProcessbar, taskCtrl, row);
                        lastshow = row;
                    }
                }
                this.BeginInvoke(TaskProcessbar, taskCtrl, taskCtrl.Endrecord);
                //將循環(huán)完后拼接好的字符串保存到txt文件里,文件名為用戶控件名稱
                string filePath = Directory.GetCurrentDirectory() + "\\file" + taskCtrl.Name + ".txt";
                System.IO.File.WriteAllText(filePath, str, Encoding.UTF8);               
            }
            return res;
        }

接下來我們運行看看效果

C#多線程Task的使用

C#多線程Task的使用

C#多線程Task的使用

任務(wù)執(zhí)行完后程序目錄下生成對應(yīng)的txt文件

C#多線程Task的使用

感謝各位的閱讀,以上就是“C#多線程Task的使用”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對C#多線程Task的使用這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI