C#基础系列——多线程 信号量 异步 编程 Task Thread async和await

摘要:
{for(vari=0;varstrResult=Task.Run<Console.WriteLine(strResult.Result);}staticstringGetReturnResult(){Thread.Sleep(2000);从结果分析中,我们可以看到varstrResult=Task.Run<varstrResult=Task.Run<

 多线程:

ThreadStart 是一个委托函数

        static void Main(string[] args)
        {
            Thread oGetArgThread = new Thread(new ThreadStart(() =>
            {

                for (var i = 0; i < 1000000; i++)
                {
                    Console.WriteLine("后台线程计数" + i);
                    Thread.Sleep(100);
                }
            }));
            oGetArgThread.IsBackground = true;
            oGetArgThread.Start();
            Console.ReadKey();
        }

Task:

1、Task对象的前世今生:Task对象是.Net Framework 4.0之后出现的异步编程的一个重要对象。在一定程度上来说,Task对象可以理解Thread对象的一个升级产品。既然是升级产品,那它肯定有他的优势,比如我们上面Thread对象不能解决的问题:对于有返回值类型的委托。Task对象就能简单的解决。

复制代码
     static void Main(string[] args)
        {
            Console.WriteLine("执行GetReturnResult方法前的时间:" + DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));
            var strRes = Task.Run<string>(() => { return GetReturnResult(); });//启动Task执行方法
            Console.WriteLine("执行GetReturnResult方法后的时间:" + DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));
            Console.WriteLine(strRes.Result);//得到方法的返回值
            Console.WriteLine("得到结果后的时间:" + DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));

            Console.ReadLine();
        }

        static string GetReturnResult()
        {
            Thread.Sleep(2000);
            return "我是返回值";
        }
复制代码

先来看结果:

C#基础系列——多线程 信号量 异步 编程 Task Thread async和await第3张

从结果分析可知在执行var strRes = Task.Run<string>(() => { return GetReturnResult(); })这一句后,主线程并没有阻塞去执行GetReturnResult()方法,而是开启了另一个线程去执行GetReturnResult()方法。直到执行strRes.Result这一句的时候主线程才会等待GetReturnResult()方法执行完毕。为什么说是开启了另一个线程,我们通过线程ID可以看得更清楚:

复制代码
     static void Main(string[] args)
        {
            Console.WriteLine("执行GetReturnResult方法前的时间:" + DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));
            var strRes = Task.Run<string>(() => { return GetReturnResult(); });
            Console.WriteLine("执行GetReturnResult方法后的时间:" + DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));
            Console.WriteLine("我是主线程,线程ID:" + Thread.CurrentThread.ManagedThreadId);
            Console.WriteLine(strRes.Result);
            Console.WriteLine("得到结果后的时间:" + DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));

            Console.ReadLine();
        }

        static string GetReturnResult()
        {
            Console.WriteLine("我是GetReturnResult里面的线程,线程ID:" + Thread.CurrentThread.ManagedThreadId);
            Thread.Sleep(2000);
            return "我是返回值";
        }
复制代码

结果:

C#基础系列——多线程 信号量 异步 编程 Task Thread async和await第6张

由此可以得知,Task.Run<string>(()=>{}).Reslut是阻塞主线程的,因为主线程要得到返回值,必须要等方法执行完成。

Task对象的用法如下:

复制代码
            //用法一
            Task task1 = new Task(new Action(MyAction));
          //用法二
            Task task2 = new Task(delegate
            {
                MyAction();
            });
        //用法三
            Task task3 = new Task(() => MyAction());
            Task task4 = new Task(() =>
            {
                MyAction();
            });

            task1.Start();
            task2.Start();
            task3.Start();
            task4.Start();
复制代码

由上可知,Task对象的构造函数传入的是一个委托,既然能传入Action类型的委托,可想而知Action的16中类型的参数又可以派上用场了。于是乎Task对象参数的传递就不用多说了吧。详见 C#基础系列——委托和设计模式(一)里面Action委托的用法。

初识 async & await。

复制代码
        static void Main(string[] args)
        {
            Console.WriteLine("我是主线程,线程ID:{0}", Thread.CurrentThread.ManagedThreadId);
            TestAsync();
            Console.ReadLine();
        }

        static async Task TestAsync()
        {
            Console.WriteLine("调用GetReturnResult()之前,线程ID:{0}。当前时间:{1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));
            var name = GetReturnResult();
            Console.WriteLine("调用GetReturnResult()之后,线程ID:{0}。当前时间:{1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));
            Console.WriteLine("得到GetReturnResult()方法的结果:{0}。当前时间:{1}", await name, DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));
        }

        static async Task<string> GetReturnResult()
        {
            Console.WriteLine("执行Task.Run之前, 线程ID:{0}", Thread.CurrentThread.ManagedThreadId);
            return await Task.Run(() =>
            {
                Thread.Sleep(3000);
                Console.WriteLine("GetReturnResult()方法里面线程ID: {0}", Thread.CurrentThread.ManagedThreadId);
                return "我是返回值";
            });
        }
复制代码

结果:

C#基础系列——多线程 信号量 异步 编程 Task Thread async和await第11张

我们来看看程序的执行过程:

C#基础系列——多线程 信号量 异步 编程 Task Thread async和await第12张

由上面的结果可以得到如下结论:

(1)在async标识的方法体里面,如果没有await关键字的出现,那么这种方法和调用普通的方法没什么区别。

(2)在async标识的方法体里面,在await关键字出现之前,还是主线程顺序调用的,直到await关键字的出现才会出现线程阻塞。

(3)await关键字可以理解为等待方法执行完毕,除了可以标记有async关键字的方法外,还能标记Task对象,表示等待该线程执行完毕。所以await关键字并不是针对于async的方法,而是针对async方法所返回给我们的Task。

(4)是否async关键字只能标识返回Task对象的方法呢。我们来试试:

C#基础系列——多线程 信号量 异步 编程 Task Thread async和await第13张

异步方法的返回类型必须为void、Task或者Task<T>类型。也就是说async要么是void,要么和Task关联。

3、除了await关键字,Task对象还有另外一种方式等待执行结果。  

复制代码
     static async Task TestAsync()
        {
            Console.WriteLine("调用GetReturnResult()之前,线程ID:{0}。当前时间:{1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));
            var name = GetReturnResult();
            Console.WriteLine("调用GetReturnResult()之后,线程ID:{0}。当前时间:{1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));
            Console.WriteLine("得到GetReturnResult()方法的结果:{0}。当前时间:{1}", name.GetAwaiter().GetResult(), DateTime.Now.ToString("yyyy-MM-dd hh:MM:ss"));
        }
复制代码

这样可以得到相同的结果。

name.GetAwaiter()这个方法得到的是一个TaskAwaiter对象,这个对象表示等待完成的异步任务的对象,并提供结果的参数。所以除了能完成await关键字的等待之外,它还能做一些其他的操作。我们将TaskAwaiter转到定义

复制代码
public struct TaskAwaiter<TResult> : ICriticalNotifyCompletion, INotifyCompletion
    {
        public bool IsCompleted { get; }
        public TResult GetResult();
        public void OnCompleted(Action continuation);
        public void UnsafeOnCompleted(Action continuation);
   }    
复制代码

IsCompleted:获取一个值,该值指示异步任务是否已完成。

GetResult():得到执行的结果。这个方法和await关键字效果相同。

OnCompleted():传入一个委托,在任务执行完成之后执行。

UnsafeOnCompleted():计划与此 awaiter 相关异步任务的延续操作。

由此可以看出,await关键字实际上就是调用了TaskAwaiter对象的GetResult()方法。

 信号量:

同时只允许一定数量的线程执行,这个数量称为信号量

using System;
using System.Threading;
using System.Threading.Tasks;

namespace MyTTCon
{
    class mysemaphore
    {
        public static void Main()
        {
            for (int i = 0; i < 20; i++)
            {
                new mythread().run(i.ToString());
            }
            Console.ReadKey();
        }
    }
    class mythread
    {
        //public Thread thrd;
        //创建一个可授权2个许可证的信号量,且初始值为2
       static Semaphore sem = new Semaphore(2, 2);
       public  void run(string Name)
        {
            
            
            Task.Run(() =>
            {
                //申请一个许可证
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":正在等待一个许可证……");
                sem.WaitOne();
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":申请到许可证……");
                Thread.Sleep(8000);
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":释放许可证……");
                sem.Release();
            });
        }
    }

}

 
http://www.cnblogs.com/landeanfen/p/4704139.html

免责声明:文章转载自《C#基础系列——多线程 信号量 异步 编程 Task Thread async和await》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇JS去除对象或数组中的空值('',null,undefined,[],{})java回调机制(同步回调)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

[转]QT子线程与主线程的信号槽通信-亲测可用!

近用QT做一个服务器,众所周知,QT的主线程必须保持畅通,才能刷新UI。所以,网络通信端采用新开线程的方式。在涉及到使用子线程更新Ui上的控件时遇到了点儿麻烦。网上提供了很多同一线程不同类间采用信号槽通信的方式,但是并不完全适合线程间的信号槽通信,这主要体现在自定义消息的传递上。 首先我们看看一般的方式:利用信号-槽发送Qt内置的元数据类型testthre...

CString用法总结

  概述:CString是MFC中提供的用于处理字符串的类,是一种很有用的数据类型。   它很大程度上简化了MFC中的许多操作,使得MFC在做字符串操作时方便了很多。   不管怎样,使用CString有很多的特殊技巧,特别对于纯C背景下走出来的程序员来说有点难以学习。 一、前言   CString位于头文件afx.h中,这篇文章就来讨论这些技巧。   参考...

java+httpclient—— 一个简单的get请求

package jkcs; import java.io.IOException; import org.apache.http.HttpEntity; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.Closeab...

QT之深入理解QThread

QT之深入理解QThread       理解QThread之前需要了解下QThread类,QThread拥有的资源如下(摘录于QT 5.1 帮助文档):       在以上资源中,本文重点关注槽:start();信号:started()、finished();受保护的方法:run()、exec();   理解QThread     QThread与通常所...

安卓进阶:元注解Support Annotation Library使用详解

Support Annotation Library是一个函数包,包含一系列有用的元注解。 注解目录:  Nullness注解  资源类型注解 类型定义注解 线程注解 RGB颜色值注解 值范围注解 权限注解 重写函数注解 返回值注解 @VisibleForTesting @Keep 实用主义至上,不记录历史和版本这些,现在直接了解一下这个函数包有什么用...

web worker 的传值方式以及耗时对比

背景 前一阵子开发的项目 pptx 导入, 由于自己的代码问题,引起了个性能问题,一个 40p 的 pptx 文件,转换成 json 数据,大概要耗时 60s+ ,虽然后面发现是某个使用频率非常高的函数内部,用了 new Function 构造函数 造成的(所以这里顺便提醒一下,如果你很在乎几毫秒的差距的话,建议谨慎使用哈),但是在优化的过程中,一度怀疑是...