C# TASK使用实例

2020-08-19 14:44:00 浏览数 (1)

代码语言:javascript复制
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 WindowsFormsApp3
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Task.Run(()=>
            {
                for (int i = 0; i < 500000000; i  )  //比较耗时的任务放到task中区执行,不然定时器等到此任务执行完才会更新界面数据
                {
                    Task th1 = new Task(test1);
                    th1.Start();
                    Task th2 = new Task(test2);
                    th2.Start();
                }
            });

        }
        int ca = 0;
        object locker = new object();
        private void test1()
        {

                lock (locker)  //由于多个task存在数据竞争,需要加锁
                {
                    this.BeginInvoke(new Action(() => {  label1.Text =  ca.ToString()   " 秒"; }));
                    ca  ;
                    Thread.Sleep(1000);
                }

        }
        private void test2()
        {

            lock (locker) //由于多个task存在数据竞争,需要加锁
            {
                this.BeginInvoke(new Action(() => { label1.Text =  ca.ToString()   " 秒"; }));
                ca  ;
                Thread.Sleep(1000);
            }

        }
    }
}

运行结果:

Task的用法

  1、创建任务

(一)无返回值的方式 方式1:

代码语言:javascript复制

  var t1 = new Task(() => TaskMethod("Task 1"));
  t1.Start();
  Task.WaitAll(t1);//等待所有任务结束 
  注:任务的状态:
  Start之前为:Created
  Start之后为:WaitingToRun 

方式2:

代码语言:javascript复制
  Task.Run(() => TaskMethod("Task 2"));

  方式3:

代码语言:javascript复制
代码语言:javascript复制
  Task.Factory.StartNew(() => TaskMethod("Task 3")); 直接异步的方法 
  //或者
  var t3=Task.Factory.StartNew(() => TaskMethod("Task 3"));
  Task.WaitAll(t3);//等待所有任务结束
  //任务的状态:
  Start之前为:Running
  Start之后为:Running

2.Task的使用简单总结

1、首次构造一个Task对象时,他的状态是Created。

2、当任务启动时,他的状态变成WaitingToRun。

3、Task在一个线程上运行时,他的状态变成Running。

4、任务停止运行,等待他的任何子任务时,状态变成WaitingForChildrenToComplete。

5、任务完全结束时,它进入以下三个状态之一:RanToCompletion,Canceled或者Faulted。

6、一个Task<TResult>运行完成时,可通过Task<TResult>的Result属性来查询任务的结果,

7、一个Task或者Task<TResult>出错时,可以查询Task的Exception属性来获得任务抛出的未处理的异常,该属性总是返回一个AggregateException对象,他包含所有未处理的异常。

8、为简化代码,Task提供了几个只读的Boolean属性,IsCanceled,IsFaulted,IsCompleted。

9、注意,当Task处于RanToCompleted,Canceled或者Faulted状态时,IsCompleted返回True。

10、为了判断一个Task是否成功完成,最简单的方法是:if(task.Status == TaskStatus.RanToCompletion)。

11、task的ContinueWith方法用于在一个任务完成后发起一个新任务。

12、任务的启动、停止与异常处理

(1)任务的启动:

代码语言:javascript复制
CancellationTokenSource cts = new CancellationTokenSource();
Task task = new Task(() => ThreadGetData(cts.Token), cts.Token);
private void ThreadGetData(CancellationToken ct)//ThreadGetData是自己的一个方法,用于每分钟读取一次数据
{
ReadDataOneMinite(ct);
}
task.Start();//任务启动

(2)任务的停止:

任务和线程并不是调用者想停止就能停止的,正确停止线程更多地在于工作线程是否能主动响应调用者的停止请求。在基于Task的任务执行过程中,我们通常使用CancellationTokenSource来实现任务取消。CancellationTokenSource 是一种名为“取消标记”的轻型对象,用于线程和任务的协作取消。线程和任务在工作的同时,会以某种频率检测CancellationTokenSource的IsCancellationRequested标识,若检测到IsCancellationRequested,线程自己负责退出。下面是线程取消的一段代码示例:

代码语言:javascript复制
CancellationTokenSource
cts =
new CancellationTokenSource();
Task task =
new Task(()
=>
{
while (true)
{
if (cts.Token.IsCancellationRequested)//如果检测到取消请求
{
Console.WriteLine("线程被终止!");
break;
}
//否则执行某工作

ReadDataOneMinite(ct);//用于每分钟读取一次数据
Thread.Sleep(60000);
}
});
task.Start();
cts.Cancel();//任务取消

调用者使用CancellationTokenSource的Cancle方法通知工作线程退出。工作线程则以大致60000毫秒的频率一边工作,一边检查是否有外界传入进来的Cancel信号。若有这样的信号,则负责退出。协作式取消中的关键类型是CancellationTokenSource。它有一个关键属性Token,Token是一个名为CancellationToken的值类型。CancellationToken继而进一步提供了布尔值的属性IsCancellationRequested作为需要取消工作的标识。

(3)任务的异常处理:

代码语言:javascript复制
CancellationTokenSource cts
=
new CancellationTokenSource();
Task
task =
new Task(()
=>
{
while (true)
{
if (cts.Token.IsCancellationRequested)//如果检测到取消请求
{
cts.Token.ThrowIfCancellationRequested();//异常处理来退出程序,但CLR知道这一行是程序员有意为之,所以并不
把它当做一个异常(它被理解为取消)
break;
}
//否则执行某工作

ReadDataOneMinite(ct);//用于每分钟读取一次数据
Thread.Sleep(60000);
}
});

以上是一些简单的使用方式,待工作中深入应用后再进行补充任务的其他使用。

0 人点赞