shou ye

.NET 多线程 Task async await

 

多线程概念

两个名词

线程不安全:多个线程访问同一段代码,产生不确定结果(冲突)

线程安全:各个线程正常且正确执行,不会出现数据污染等意外

 

多线程的例子

例1:两个线程同时打印

        static void Main(string[] args)
        {
            Method1();
            Method2();
            Console.WriteLine(" main end ");
            Console.ReadKey();
        }

        public static async Task Method1()
        {
            await Task.Run(() =>
            {
                for (int i = 0; i < 50; i++)
                {
                    Task.Delay(500).Wait();
                    Console.WriteLine(" Method 1");
                }
            });
        }

        public static void Method2()
        {
            for (int i = 0; i < 20; i++)
            {
                Task.Delay(1000).Wait();
                Console.WriteLine(" Method 2");
            }
        }

输出

 

 例子2:存在依赖支线线程的主线程

Method3 需要一个从 Method1 返回来的 int 数,用 await 等待返回的结果。

        static void Main(string[] args)
        {
            callMethod();
            Console.ReadKey();
        }

        public static async void callMethod()
        {
            Task<int> task = Method1();

            Method2();
            int count = await task; //或者写 task.Result; //主线程会停在这一步
            Console.WriteLine("call end");

            Method3(count);
        }

        public static async Task<int> Method1()
        {
            int count = 0;
            await Task.Run(() =>
            {
                for (int i = 0; i < 50; i++)
                {
                    Task.Delay(100).Wait();
                    Console.WriteLine(" Method 1");
                    count += 1; 
                }
            });
            return count;
        }

        public static void Method2()
        {
            for (int i = 0; i < 20; i++)
            {
                Task.Delay(200).Wait();
                Console.WriteLine(" Method 2");
            }
        }

        public static void Method3(int count)
        {
            Console.WriteLine("Total count is " + count);
        }

输出

 

Task相关

官方文档传送门

Task 开启一个新任务

开启后台线程:Task.Run() 或者 Task.Factory.StartNew()

以 Task.Run() 开启一个新任务

//返回值类型为string
Task<string> task = Task<string>.Run(() => {
    Thread.Sleep(2000);  //或 Task.Delay(2000).Wait();
    return Thread.CurrentThread.ManagedThreadId.ToString(); 
});
//会等到task执行完毕才会输出;
Console.WriteLine(task.Result); //task.Result 可改成 await task

Task.Factory.StartNew() 可以使用比 Task.Run() 更多的参数,可以做更多定制(如长时间运行)。 参考传送门

Task.Factory.StartNew(() =>
{
    Console.WriteLine("进行 线程" + Thread.CurrentThread.ManagedThreadId);
}, TaskCreationOptions.LongRunning); //设置线程是长时间运行的,这时线程池就不会等待这个线程回收

 

注:Task 任务可以通过 CancellationTokenSource 类来取消。

Task.Wait() 和 await Task

Task.Wait()  阻塞线程,等待期间,系统不会对其他操作响应

await Task  等待任务完成,等待期间,系统可以响应其他操作

Task.Delay() 和 Thread.Sleep()

参考传送门

1、Thread.Sleep 是同步延迟,Task.Delay异步延迟。

2、Thread.Sleep 会阻塞线程,Task.Delay不会。

3、Thread.Sleep不能取消,Task.Delay可以。

4. Task.Delay() 比 Thread.Sleep() 消耗更多的资源,但是Task.Delay()可用于为方法返回Task类型;或者根据CancellationToken取消标记动态取消等待

5. Task.Delay() 实质创建一个运行给定时间的任务, Thread.Sleep() 使当前线程休眠给定时间。

有条件的 Task

Task 内部提供多种多样的基于队列的链式任务管理方法,通过使用这些快捷方式,可以让异步队列有序的执行,比如 ContinueWith(),ContinueWhenAll(),ContinueWhenAny(),WaitAll(),WaitAny(),WhenAll(),WhenAny()

Task.WaitAll(t1, t2)  等待多个线程

Task.WaitAny(t1, t2)  等待任意一个线程

Task.WhenAll(t1, t2)  创建一个任务,任务会在集合中的所有 Task 对象都完成时完成(不会主动等待)

var tasks = new List<Task>();
tasks.Add(Task.Run( () => { Task.Delay(1000).Wait(); Console.WriteLine("1"); } ));
tasks.Add(Task.Run( () => { Task.Delay(2000).Wait(); Console.WriteLine("2"); } ));
Task t = Task.WhenAll(tasks);
t.Wait();
Console.WriteLine("3");

这里的输出顺序为:

1
2
3

Task.WhenAny(t1, t2)  任一任务完成时,创建将完成的任务(返回第一项完成的任务)。 

var tasks = new List<Task>();
tasks.Add(Task.Run( () => { Task.Delay(1000).Wait(); Console.WriteLine("1"); } ));
tasks.Add(Task.Run( () => { Task.Delay(2000).Wait(); Console.WriteLine("2"); } ));
Task t = Task.WhenAny(tasks);
t.Wait();
Console.WriteLine("3");

这里的输出顺序为:

1
3
2

 

async 和 await 异步编程

1、凡是使用 await 关键字的方法,都必须打上 async 标记

2、async 标识方法内有异步方法,调用 async 方法,会立刻另起线程执行

3、await 只是显示等待线程结束:await 表示等待异步方法执行完,并取返回值

 

参考来源

https://www.cnblogs.com/doforfuture/p/6293926.html (Mr靖 的 C#中 Thread,Task,Async/Await,IAsyncResult 的那些事儿!)

https://www.cnblogs.com/zhao123/p/9999607.html (凌风95 的 C# Task.Run 和 Task.Factory.StartNew 区别)

https://www.cnblogs.com/yy1234/p/8073732.html (禅道 的 Task.Delay() 和 Thread.Sleep() 区别)

https://www.cnblogs.com/ma8023/p/11677394.html (逆骨苍狼 的 C# 中的Async 和 Await 的用法详解)

https://www.cnblogs.com/wangwust/p/9474786.html (wangwust 的 【.NET】- async await 异步编程)

https://www.cnblogs.com/viter/p/10201228.html (Ron Liang 的 Asp.Net Core 轻松学-多线程之Task快速上手)

posted @ 2021-01-08 22:04  芦荟柚子茶  阅读(546)  评论(0编辑  收藏  举报
ye jiao