异步与线程阻塞

简介:

应该这样理解它

异步,早期开发人员对它有很多误解,认为不阻塞主线程就是异步,更有认为不阻塞UI就是异步,但异步归根结底和这两个东西关系并不大,异步的出现主要是为了提高线程的利用率,让可用线程更高,而不是一个线程只做一件事,这件事没有完成就不去做下面的事情,这是不正确的,线程应该被解放出来!事实上,你如果学过nodejs的话,对单线程非阻塞应该更清楚一些,它主要通过方法回调来实现异步的,只是在语法上和C#不太一样。

说一下上面提到的误解

误解1:不阻塞主线程

如果不阻塞主线程的话,你只能开个新线程完成这个动作,像一些系统通知,它和主线程的工作流程没有关系,如果开个新线程,与主线程并行执行,这并不是我们说的异步,这只是多线程!它会增加线程的开支,使用不当,会影响系统的吞吐量!

误解2:不阻塞UI

这就更属于胡扯了,对于一个工作流来说,必须要按着1,2,3的顺序去执行,如果是同步代码,它是一个线程从1执行到3,这个线程将一直被占用!如果是异步代码,它在执行到1时,线程被回收到池子,其它人可以使用,当1执行完成后,从线程池里取出一个新的线程继续执行,这叫异步!C#的异步进行友好,使用async,await就可以实现了!

实验:查看有效的线程剩余数

        // <summary>
        /// 线程非阻塞,线程利用率高
        /// 线程await后可以去做其它事
        /// 然后await后面方法结束后再申请新线程执行下面的代码
        /// </summary>
        /// <returns></returns>
        [Route("~/do5")]
        public async Task<string> Do5()
        {
            var sw = new Stopwatch();
            sw.Start();
            await HttpHelper.Get("http://localhost:61699/do1");
            await HttpHelper.Get("http://localhost:61699/do2");
            await HttpHelper.Get("http://localhost:61699/do3");
            await HttpHelper.Get("http://localhost:61699/do4");
            sw.Stop();
            int workerThreads, completionPortThreads;
            ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
            return $"max threads:{workerThreads},completionPortThreads:{completionPortThreads},timer:{sw.ElapsedMilliseconds.ToString()}";
        }

我们来看它的I/O线程剩余,多刷新几次,一直维持在32766和32765之间

而如果使用同步代码,结果就完成不一样了,线程剩余各位可以看下面

线程ID在每个await时是不同的

下面是一个更明显的测试,依次执行多个await,然后获取当前线程的ID,它们在异步环境下,有可能是不同的,因为每次都要从池子里拿新的线程!

            await HttpHelper.Get("http://localhost:61699/do1");
            str.Append($"step1:{Thread.CurrentThread.ManagedThreadId}");
            await HttpHelper.Get("http://localhost:61699/do2");
            str.Append($"step2:{Thread.CurrentThread.ManagedThreadId}");
            await HttpHelper.Get("http://localhost:61699/do3");
            str.Append($"step3:{Thread.CurrentThread.ManagedThreadId}");
            await HttpHelper.Get("http://localhost:61699/do4");
            str.Append($"step4:{Thread.CurrentThread.ManagedThreadId}");

通过这篇文章,我们应该真正理解异步这个概念了吧,记住,异步主要为了提高线程利用率,从而提高系统的吞吐量的,它与并行,主线程阻塞很有直接关系,也不是它所研究的重点,这个大家一定要记住!

本文转自博客园张占岭(仓储大叔)的博客,原文链接:异步与线程阻塞,如需转载请自行联系原博主。

目录
相关文章
|
3月前
|
Python
【Python30天速成计划】10.异步以及多进程和多线程
【Python30天速成计划】10.异步以及多进程和多线程
|
6月前
|
安全 Java
【JavaSE专栏76】三态和五态,线程的不同状态:新建、运行、状态、阻塞、等待、计时等待状态
【JavaSE专栏76】三态和五态,线程的不同状态:新建、运行、状态、阻塞、等待、计时等待状态
|
7月前
|
Arthas IDE Java
一种获取阻塞线程栈帧数据的思路
一种获取阻塞线程栈帧数据的思路
125 1
|
28天前
|
Python
Python学习之路 02 之分支结构
Python学习之路 02 之分支结构
47 0
Python学习之路 02 之分支结构
|
28天前
|
Java Python 开发者
Python 学习之路 01基础入门---【Python安装,Python程序基本组成】
线程池详解与异步任务编排使用案例-xian-cheng-chi-xiang-jie-yu-yi-bu-ren-wu-bian-pai-shi-yong-an-li
76 2
Python 学习之路 01基础入门---【Python安装,Python程序基本组成】
|
30天前
|
消息中间件 Linux 调度
【Linux 进程/线程状态 】深入理解Linux C++中的进程/线程状态:阻塞,休眠,僵死
【Linux 进程/线程状态 】深入理解Linux C++中的进程/线程状态:阻塞,休眠,僵死
67 0
|
1天前
|
监控
写一个线程来监控各线程是否发生阻塞
写一个线程来监控各线程是否发生阻塞
7 0
|
23天前
|
JavaScript 前端开发
JS 单线程还是多线程,如何显示异步操作
JS 单线程还是多线程,如何显示异步操作
22 2
|
1月前
|
JavaScript Java API
spring boot使用异步多线程
一文讲清楚spring boot如何结合异步多线程实现文件的导出这类耗时间的操作优化以及常用的场景,了解异步思想
30 0
spring boot使用异步多线程
|
1月前
|
Java
多线程------Future异步任务
多线程------Future异步任务

热门文章

最新文章