很久以前的一个面试场景:

面试官:说说你对JavaScript闭包的理解吧?

我:嗯,平时都是前端工程师在写JS,我们一般只管写后端代码。

面试官:你是后端程序员啊,好吧,那问问你多线程编程的问题吧。

我:一般没用到多线程。

面试官:............................. (面试结束)

好了,哈哈一笑后,我们来看看 Thread,ThreadPool,Task, async, await 的基本使用方法。

1.Thread

        private static void Main(string[] args)
{
System.Console.WriteLine("主线程开始");
var thread = new Thread(new ThreadStart(ThreadTest));
thread.Start(); System.Console.WriteLine("主线程结束");
System.Console.ReadLine();
} private static void ThreadTest()
{
System.Console.WriteLine("开始执行子线程.... ");
Thread.Sleep();
}

执行结果:

上面的代码,大家应该都很好理解,通过new Thread 来创建一个子线程,然后.Start() 开始执行。

我们F12 ThreadStart 看到 public delegate void ThreadStart();  是一个无参数无返回值的委托,那么,如果要在线程中执行一个有参数的方法怎么办了?

OK,我们看Thread的构造函数

ParameterizedThreadStart 是什么?按字面上意思就是带参数的ThreadStart,继续F12看看它

果然是可以带一个object的参数。

改造一下刚才的代码:

        private static void Main(string[] args)
{
System.Console.WriteLine("主线程开始");
var thread = new Thread(new ParameterizedThreadStart(ThreadTest));
thread.Start(); System.Console.WriteLine("主线程结束");
System.Console.ReadLine();
} private static void ThreadTest(object p)
{
System.Console.WriteLine("开始执行子线程.... 参数:{0} ", p);
Thread.Sleep();

执行结果:

(当然还可以用ThreadStart(()=>{ }) 直接用lambda表达式的方式,这里就不写示例代码了 )

看到上面的执行结果,子线程因为Thread.Sleep(100) ,所以每次都最后才打印出输出结果,那么你可能会疑问,如果我想等子线程执行完,我再执行主线程后面的代码,怎么办?

        private static void Main(string[] args)
{
System.Console.WriteLine("主线程开始");
var thread = new Thread(new ParameterizedThreadStart(ThreadTest));
thread.Start();
thread.Join(); System.Console.WriteLine("主线程结束");
System.Console.ReadLine();
}
private static void ThreadTest(object p)
{
System.Console.WriteLine("开始执行子线程.... 参数:{0} ", p);
Thread.Sleep();
}

注意看, 加了这句 thread.Join() ,管他什么意思,我们先看看执行结果吧!

OK,是不是明白Join()的意义了?

2.ThreadPool

为什么有了Thread还要出现ThreadPool了?

 如果你的代码设计了大量使用Thread,那么有可能会超过系统最大的线程数导致崩溃,而且每次创建和销毁线程也是很耗资源,ThreadPool就可以帮你提高代码效率并管理你的线程。

这不是重点,今天重点是学习它的基础使用方法。

        private static void Main(string[] args)
{
System.Console.WriteLine("主线程开始");
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadTest), ); System.Console.WriteLine("主线程结束");
System.Console.ReadLine();
} private static void ThreadTest(object p)
{
System.Console.WriteLine("开始执行子线程.... 参数:{0} ", p);
Thread.Sleep();
}

先看看WaitCallback的定义

一个带参数的委托,这就要求它的委托方法必须带一个object的参数了。

ThreadPool静态类通过QueueUserWorkItem()方法将工作函数排入线程池,它不需要我们主动的.Start(),那么他能不能Join()了?

我们点一下就知道了,它既不要你手动Start也没有Join这样的方法。

好了,简单学习Thread和ThreadPool后,发现他们构造函数中都是没有返回值的委托,如果我们要在主线程中获取子线程执行方法的返回值,怎么办? Task闪亮登场了!

3.Task

        private static void Main(string[] args)
{
System.Console.WriteLine("主线程开始");
// new Task 创建方式-不带参数
//Task task = new Task(ThreadTest);
//task.Start(); // new Task 创建方式-带参数
//Task task=new Task(() => ThreadTest(10)); //Task.Factory 创建方式-不带参数
//Task task = Task.Factory.StartNew(ThreadTest);
//task.Start(); //Task.Factory 创建方式-带参数
//Task task = Task.Factory.StartNew(() => ThreadTest(10));
//task.Start(); Task task = Task.Run(() => ThreadTest());
//Task task = Task.Run(() => ThreadTest(10)); System.Console.WriteLine("主线程结束");
System.Console.ReadLine();

Task 的三种创建线程的方法,Task.Run() 不需要手动Start() 。其他两种方式是需要手动Start()。 他们没有Join()方法,取而代之的是Wait()

我们用Run()方法为例,看Task如何获取方法的返回值。

        private static void Main(string[] args)
{
System.Console.WriteLine("主线程开始"); Task<int> task = Task.Run(() => ThreadTest());
var result = task.Result; System.Console.WriteLine("主线程结束,result={0}", result);
System.Console.ReadLine();
} private static int ThreadTest(int i)
{
Thread.Sleep();
System.Console.WriteLine("子线程开始");
return i * ;
}

执行结果:

通过task.Result 我们获取到了在子线程中ThreadTest方法的返回值。有没有注意,主线程是等子线程执行完之后才打印最后输出的! task.Result 除了拿到返回值外,是不是和Wait()类似?

看到这里,你肯定会想到,这样另起线程去跑耗时作业和我们平时普通写法有什么区别?效率上会高很多吗?我们来测试看看!

常规方法:

        private static void Main(string[] args)
{
DateTime dt1 = DateTime.Now;
int count = ;
for (int i = ; i < ; i++)
{
Thread.Sleep();
count += i;
}
System.Console.WriteLine("执行完成,耗时=" + (DateTime.Now - dt1).TotalMilliseconds);
System.Console.ReadLine();
}

Task方法:

        private static void Main(string[] args)
{
DateTime dt1 = DateTime.Now;
Task<int> task = Task.Run(() =>
{
int count = ;
for (int i = ; i < ; i++)
{
Thread.Sleep();
count += i;
}
return count;
}); var result = task.Result; System.Console.WriteLine("执行完成,耗时=" + (DateTime.Now - dt1).TotalMilliseconds);
System.Console.ReadLine();
}

这就很尴尬了,用Task反而执行时间更长!!!  是不是我的打开方式不对?

4.async  await

async是修饰一个异步方法的关键字。有两种返回类型(void 或者 Task<T>)

await必须是在async修饰的异步方法体内,await后面必须是一个异步方法或者Task。表示异步等待后面方法的结果。

1.返回void的使用方法

        private static void Main(string[] args)
{
System.Console.WriteLine("主线程开始");
for (int i = ; i < ; i++)
{
ThreadTest(i);
}
System.Console.WriteLine("主线程执行完成");
System.Console.ReadLine();
} private static async void ThreadTest(int i)
{
await Task.Run(() =>
{
Thread.Sleep();
System.Console.WriteLine("子线程开始,i=" + i);
});
}

执行结果

2.返回Task<T>的使用方法

        private static void Main(string[] args)
{
System.Console.WriteLine("主线程开始");
var task = ThreadTest();
System.Console.WriteLine("主线程执行完成,result="+ task.Result);
System.Console.ReadLine();
}
private static async Task<int> ThreadTest()
{
var count = ;
await Task.Run(() =>
{
for (int i = ; i < ; i++)
{
Thread.Sleep();
count += i;
System.Console.WriteLine("count="+ count);
}
});
return count;
}

返回的是Task<T>,那么像得到它的返回值,肯定也是通过.Result了,我们肯定有疑问了,这样和直接写Task有什么区别? 只是为了更加方便和美观吗?

接下来我们来测试下执行效率!

        private static void Main(string[] args)
{
DateTime dt1 = DateTime.Now;
var t = ThreadTest().Result;
System.Console.WriteLine("执行完成,耗时=" + (DateTime.Now - dt1).TotalMilliseconds + " count=" + t);
System.Console.ReadLine();
} private static async Task<int> ThreadTest()
{
var count = ;
await Task.Run(() =>
{
for (int i = ; i < ; i++)
{
Thread.Sleep();
count += i;
}
});
return count;
}

执行效率和之前没什么区别,不知道这种测试方式是否合理?跪求大神们分享赐教!

今天就写到这里,关于 async  await 和Task区别,async  await 线程阻塞问题,后面再来仔细研究。

========================================================================================================

分割线

========================================================================================================

昨天这篇博客发布后,收到大神的批评和指教,非常感谢!

读了这篇文章后,才恍然大悟。 文章链接:https://msdn.microsoft.com/zh-cn/magazine/jj991977.aspx

分析下昨天测试“性能”的实例代码的使用错误:

1.盲目使用task.Result来获取最终结果,这样导致主线程阻塞,都是等待子线程执行完毕。这样的时间差比没有太多意义。

2.都是在一个Task.Run()中模拟一个耗时操作,内部循环Thread.Sleep(10)。这样把耗时操作搬到一个子线程去做,就算快也能快到哪里去了,完全没有体现出多线程的优越性。

下面是修改后的测试代码,再看看async await给程序带来的性能:

1.普通Task,通过task.Result获取返回值。

        private static void Main(string[] args)
{
DateTime dt1 = DateTime.Now; for (int i = ; i <= ; i++)
{
var re = Task.Run(() =>
{
Thread.Sleep();
return i;
}).Result; System.Console.WriteLine("result=" + re); if (i == )
System.Console.WriteLine("执行完成,耗时=" + (DateTime.Now - dt1).TotalMilliseconds);
}
System.Console.ReadLine();
}

2.使用async await

        private static void Main(string[] args)
{
DateTime dt1 = DateTime.Now; for (int i = ; i <= ; i++)
{
var task = ThreadTest(dt1, i);
} System.Console.ReadLine();
} private static async Task<int> ThreadTest(DateTime dt1, int i)
{
int re = await Task.Run(() =>
{
Thread.Sleep();
return i;
}); System.Console.WriteLine("result=" + re); if (i == )
System.Console.WriteLine("执行完成,耗时=" + (DateTime.Now - dt1).TotalMilliseconds); return re;
}

async await 真正体现了它的性能所在 。

总结:

1.不要盲目使用task.Result

2.async await的意义(或者说和Task的区别)在于不阻塞线程的情况下获取返回值。

本文博客园地址:http://www.cnblogs.com/struggle999/p/6933376.html

从Thread,ThreadPool,Task, 到async await 的基本使用方法解读的更多相关文章

  1. Thread,ThreadPool,Task, 到async await 的基本使用方法和理解

    很久以前的一个面试场景: 面试官:说说你对JavaScript闭包的理解吧? 我:嗯,平时都是前端工程师在写JS,我们一般只管写后端代码. 面试官:你是后端程序员啊,好吧,那问问你多线程编程的问题吧. ...

  2. 浅析C#中的Thread ThreadPool Task和async/await

    .net 项目中不可避免地要与线程打交道,目的都是实现异步.并发.从最开始的new Thread()入门,到后来的Task.Run(),如今在使用async/await的时候却有很多疑问. 先来看一段 ...

  3. C#中 Thread,Task,Async/Await,IAsyncResult 的那些事儿!

    说起异步,Thread,Task,async/await,IAsyncResult 这些东西肯定是绕不开的,今天就来依次聊聊他们 1.线程(Thread) 多线程的意义在于一个应用程序中,有多个执行部 ...

  4. C#中 Thread,Task,Async/Await,IAsyncResult 的那些事儿![转载]

    说起异步,Thread,Task,async/await,IAsyncResult 这些东西肯定是绕不开的,今天就来依次聊聊他们 1.线程(Thread) 多线程的意义在于一个应用程序中,有多个执行部 ...

  5. 详解C#中 Thread,Task,Async/Await,IAsyncResult的那些事儿

    说起异步,Thread,Task,async/await,IAsyncResult 这些东西肯定是绕不开的,今天就来依次聊聊他们 1.线程(Thread) 多线程的意义在于一个应用程序中,有多个执行部 ...

  6. C#中 Thread,Task,Async/Await 异步编程

    什么是异步 同步和异步主要用于修饰方法.当一个方法被调用时,调用者需要等待该方法执行完毕并返回才能继续执行,我们称这个方法是同步方法:当一个方法被调用时立即返回,并获取一个线程执行该方法内部的业务,调 ...

  7. thread、Task、async & await

    学习 Jesse 的文章 async & await 的前世今生(Updated) 而来 Thread是最开始使用的多线程.new一个Thread对象,将方法传进去.手动Start() 还可以 ...

  8. Thread,Task,async/await,IAsyncResult

    1.线程(Thread) 多线程的意义在于一个应用程序中,有多个执行部分可以同时执行:对于比较耗时的操作(例如io,数据库操作),或者等待响应(如WCF通信)的操作,可以单独开启后台线程来执行,这样主 ...

  9. c#中@标志的作用 C#通过序列化实现深表复制 细说并发编程-TPL 大数据量下DataTable To List效率对比 【转载】C#工具类:实现文件操作File的工具类 异步多线程 Async .net 多线程 Thread ThreadPool Task .Net 反射学习

    c#中@标志的作用   参考微软官方文档-特殊字符@,地址 https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/toke ...

随机推荐

  1. kafka分布式消息队列介绍以及集群安装

    简介 首先简单说下对kafka的理解: 1.kafka是一个分布式的消息缓存系统: 2.kafka集群中的服务器节点都被称作broker 3.kafka的客户端分为:一是producer(消息生产者) ...

  2. tmux鼠标配置出现错误unknown option: mode-mouse

    setw -g mode-mouse on set -g mouse-select-pane on set -g mouse-resize-pane on set -g mouse-select-wi ...

  3. Jquery对复选框CheckBox的操作

    checkbox: 多选框 //获取选中值  checkbox:$("#checkbox_id").attr("value"): 多选框checkbox,打勾: ...

  4. 在eclipse中使用Maven建web工程项目

    在eclipse中使用Maven建web工程项目: 第一种方式: 右键新建maven工程,勾选创建一个简单工程 填入信息,注意打包方式要改为war 点击完成,创建完的工程目录如下: 项目中没有WEB- ...

  5. Css清除浮动最优方式之一

    ---恢复内容开始--- .container:before, .container:after { display: table; content: " "; } .contai ...

  6. NSString 为什么要使用copy,而不是retain

    NSString 为什么要使用copy,而不是retain1.首先如果使用retain,只是引用计数+1,并没有生成新的对象,所以效率好2.但是使用copy安全.因为NSString 为 NSMuta ...

  7. sizeof 与 strlen

    一.sizeof     sizeof(...)是运算符,其值在编译时即计算好了,参数可以是数组.指针.类型.对象.函数等.    它的功能是:获得保证能容纳实现所建立的最大对象的字节大小.    由 ...

  8. ue4竖排文本显示

    最近发现中国风游戏中,经常会遇到旁白文字竖着显示的需求. 于是我首先找了找控件蓝图中的text有没有相关类似横竖文本框的选项,然而并无所获. 突然间灵机一动! 竖着显示不就是每个字一换行嘛! 说干就干 ...

  9. oh-my-zsh 安装和使用

    oh-my-zsh是github用户robbyrussell的一款为简化zsh配置而开发的开源项目. 其github地址:https://github.com/robbyrussell/oh-my-z ...

  10. 基于Prism.Windows的UWP开发备忘

    以前做UWP开发都是使用MvvmLight,主要是简单易上手,同时也写了很多MvvmLight的开发系列文章: UWP开发必备以及常用知识点总结 UWP开发之Mvvmlight实践九:基于MVVM的项 ...