C# 线程 异步

目录

 

Join()  

Sleep()

ThreadState 线程状态

线程安全

前台线程与后台线程

优先级

信号

Synchronization Contexts

线程池Tread Pool

Task

Task是Task的泛型子类

Continuation

TaskCompletionSource

await

  cancellation

进度Progress

组合Task


 


Join()  

join方法可以让当前线程等待join线程执行结束后再继续,

例如:A线程中,调用B线程的join方法,那么直到B线程执行完毕,才会执行A线程

join还有一个传参timespan的方法

static void Main(string[] args)
        {
            Thread t = new Thread(() =>{
                for(int i = 0; i < 100; i++)
                {
                    Debug.Write(i);
                }
            });
            //也可以用new Thread(Go);
            t.Start();
            t.Join();
            Debug.WriteLine("main");
            //将会先输出1-100 然后输出main
        }


static void Go()
        {
            for(int i = 0; i < 100; i++)
            {
                Debug.Write(i);
            }
        }

Sleep()

强制当前线程休眠,静态方法,传参可以是毫秒也可以是timespan

Thread.Sleep(2000);//当前进程休眠2秒

Thread.Sleep(0)会立马放弃当前时间片,执行交给其他线程类似Yield

Thread.Yield()线程放弃当前时间片,会把执行交给同一CPU的其他线程

 

ThreadState 线程状态

枚举值如下

  • Running  线程正常运行
  • Unstarted  线程还未开始,请调用start方法
  • WaitSleepJoin   线程因为调用Wait() Sleep() Join()方法阻塞
  • Stopped  线程停止
  • StopRequested  线程被要求停止
  • Suspended   线程被挂起,可以使用Resume()方法唤醒
  • SuspendRequested  线程被要求挂起
  • Aborted  中止
  • AbortRequested  线程被要求中止
  • Background  和线程的IsBackground属性有关,标记线程是后台线程(区别于前台线程)

    ThreadState

     

线程安全

主要关注多个线程共享数据

Local:CLR为每个线程分配自己的内存栈,是本地变量保持独立

Shared:多个线程引用同一个对象实例,那么共享实例数据。

lamda表达式和静态字段也会引起数据共享

尽可能避免使用共享数据状态

简单的处理办法是加锁lock

各种锁先不展开讲

前台线程与后台线程

默认手动创建的线程都是前台线程。

一旦所有前台线程都停止了,那么程序也停止了!

用线程的IsBackground属性来判断是不是前台线程!

应用程序无法退出的原因经常是因为还有活跃的前台线程

优先级

线程的Priority属性,是枚举值

Lowest

BelowNormal

Normal

AboveNormal

Highest

如果要提升进程的优先级,那么要使用Process.GetCurrentProcess()进程,来提升进程优先级

p.PriorityClass=ProcessPriorityClass.High;

提升优先级可能会影响其他线程

信号

有时需要让线程一直等待,直到收到信号(signaling)

简单信号类ManualResetEvent

线程中收到信号对象的WaitOne()方法的时候,线程会处于等待状态

收到信号对象的Set()方法之后,线程会继续执行

可以再调用Reset()方法,再次关闭信号

Synchronization Contexts

同步上下文System.ComponentModel空间下的抽象列

是Tread Marshaling得到泛化(数据在线程间传输)

线程池Tread Pool

减少创建线程的开销!

  1. 不可以设置线程池名称
  2. 线程池是后台线程
  3. 阻塞线程池可能让性能降级
Debug.WriteLine(Thread.CurrentThread.IsThreadPoolThread);//检测当前线程是否属于线程池

线程池中的整洁

避免线程池中的超额订阅,超额订阅非常影响CPU性能

CLR采取任务排队节流限制来避免超额订阅

 

Task

Task类解决Thread的join切换线程麻烦,传入传出数据难以获取的问题

Task是一个并发操作的相对高级的抽象(类似于封装了Thead ThreadPool)

Task.Run(委托)

Task默认使用线程池(后台线程!

task.Wait()会让task完成执行!类似于thread的join方法

Task task=Task.Run(......);

task.Wait();

 task适合短时间的任务,长时间的任务另找办法!

Task<TResult>是Task的泛型子类

使用Func<TResult>委托或者兼容的Lambda表达式来调用Task.Run就可以得到Task<TResult>

随后,可以通过Result属性来获得返回结果。

如果task还没完成操作,访问Result属性会导致进程阻塞直到task任务执行完成。

            Task<int> task = Task.Run(() =>
            {
                Thread.Sleep(3000);
                return 1;
            });
            int result = task.Result;
            Debug.WriteLine("testTask=" + result);

 

Continuation

回调

task对象的GetAwaiter方法会返回一个Awaiter对象

Awaiter对象的OnCompleted方法,会告诉task执行完/故障的时候,执行这个委托。

ContinueWith对于并行编程非常有用

TaskCompletionSource

创建task的一种方式,

        TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
            new Thread(() =>
              {
                  Thread.Sleep(5000);
                  tcs.SetResult(50);
              })
            {
                IsBackground = true
            }.Start();
            Task<int> t2 = tcs.Task;
            Debug.WriteLine("result==========="+t2.Result);

创建task并不占用线程!直到OnCompleted才占用!

一定是泛型!!

Task.Delay(5000)相当于异步版本的Thread.Sleep

Task.Delay(5000).GetAwaiter().OnCompleted(()=>Debug.WriteLine(0)));

web服务器接口功能一般都建议使用异步编程 来完成

await

简化了continuation的过程

var result=await expression;

statement(s);

就相当于

var awaiter=expression.GetAwaiter();

awaiter.OnCompleted(()=>{

    var result=awaiter.GetResult();

    statement(s);

});

如果一个方法是返回Task<T>的异步方法,调用时使用await关键字才能进行异步调用。

async修饰符,只能用于方法和lambda表达式,用来让编译器把await当做关键之而不是标识符,方法可以返回void、Task、Task<T>

一般用Task代替void返回

使用async修饰的方法叫异步方法。

async和await让异步编程的写法和同步的差不多,简化了异步编程的代码

对比一下正常代码和async+await代码:方便理解

        static async Task Main(string[] args)
        {

            await Task.Run(() =>
            {
                for (int x = 0; x < 100; x++)
                {
                    Debug.WriteLine("x=" + x);
                }
            });
            for (int y = 0; y < 100; y++)
            {
                Debug.WriteLine("y=" + y);
            }
        }
        //以上代码  会先输出x=0~99  再输出y=0~99
    
        //下面的代码  x和y会交替输出
        static void Main(string[] args)
        {

            Task.Run(() =>
            {
                for (int x = 0; x < 100; x++)
                {
                    Debug.WriteLine("x=" + x);
                }
            });
            for (int y = 0; y < 100; y++)
            {
                Debug.WriteLine("y=" + y);
            }
        }

  cancellation

使用取消标识来实现对并发进行取消。

    public class CacellationToken
    {
        //标识是否被取消
        public bool IsCancellationRequested { get; private set; }
        //调用者想取消的时候,会调用Cancel方法,这样会修改IsCancellationRequested为true
        public void Cancel() { IsCancellationRequested = true; }
        //调用者方法会通过Throw方法引发错误
        public void ThrowIfCancellationRequested()
        {
            if (IsCancellationRequested)
                throw new OperationCanceledException();
        }
    }

CLR提供了CancellationToken类+CancellationSource类(负责Cancel方法)

var cancelSource=new CancellationTokenSource();

Task func=Func(cancelSource.Token);

...

cancelSource.Cancel();

CancellationTokenSource还可以传递毫秒值,指定时间后取消

CancellationToken还提供了Register方法,可以注册一个回调委托,这个委托会在取消时触发(比如执行失败,返回请求失败)

它会返回一个对象,对象在取消注册的时候可以被Dispose掉

无论是故障Task还是取消的Task,都会传回一个OperationCanceledException

进度Progress

异步方法进度控制 先不说 IProgress<T>

组合Task

WhenAny 返回最先完成的Task  先了解概念不详细研究

WhenAll  参数所有Task都完成后,会返回一个Task   await Task.WhenAll(Delay1(),Delay2(),Delay3())  先了解概念不详细研究

可以编写自定义的任务组合器

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值