“抢先式多任务”“协同式多任务”
在“多任务”一文中,我们提到了“协同式多任务”与“抢先式多任务”的概念和二者的区别,谈到现在主流的多任务实现是“抢先式多任务”,并且留下关于未来“协同式多任务”是否会被淘汰的疑问。今天在此再举几个例子作对比,为前面提出的疑问做个推测。
第一个例子先来看看“抢先式多任务”程序的运行表现。在这个例子中,我们用C#创建一个console程序,这个程序要做的事很简单,就是在命令行窗口记录下从程序启动到做完一个正整数累加(从1累加到50亿)的时间,程序代码如下:
1 class WasteTime 2 { 3 public void run() 4 { 5 Int64 j; 6 7 for (Int64 i = 0; i < 5000000000; i++) 8 { 9 j = i; 10 } 11 } 12 }
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Console.Write("Start : "); 6 Console.WriteLine(DateTime.Now.ToLongTimeString()); 7 8 /* 9 // Method 1 10 // Simple Loop 11 12 Int64 j; 13 14 for (Int64 i = 0; i < 5000000000; i++) 15 { 16 j = i; 17 } 18 */ 19 20 21 /* 22 // Method 2 23 // Using Object 24 25 26 WasteTime w1 = new WasteTime(); 27 w1.run(); 28 29 WasteTime w2 = new WasteTime(); 30 w2.run(); 31 */ 32 33 34 /*// method 3 35 // multithreads 36 */ 37 WasteTime w1 = new WasteTime(); 38 WasteTime w2 = new WasteTime(); 39 40 Thread t1 = new Thread(new ThreadStart(w1.run)); 41 Thread t2 = new Thread(new ThreadStart(w2.run)); 42 43 t1.Start(); 44 t2.Start(); 45 46 t1.Join(); 47 t2.Join(); 48 49 50 Console.Write("Finish : "); 51 Console.WriteLine(DateTime.Now.ToLongTimeString()); 52 53 54 Console.ReadKey(); 55 } 56 }
分别用三种不同的方法,得到如下的结果:
Method1 |
Method2 |
Method3 |
|
时间 |
13s |
27s |
16s |
Cpu 使 用 率 情 况 |
注:以上数据在i5 3230m CPU电脑测试,测试过程中仅开启Visual Studio和资源监视器,图像右侧小部分曲线为开启截图软件导致
根据记录,可以看到如下现象:
1、 Method2和method3完成的工作量都是method1的两倍;
2、 method2大概用了method1两倍的时间做完累加运算;
3、 method3做完累加运算所需时间比method1多,但远比method2少;
4、 method1和method2在运算过程中都分别占用了一个cpu核心;
5、 method3在运算过程中占用了两个cpu核心;
分析以上现象,得到结论:在单线程的情况下,程序完成相同的运算所需时间基本相同,且在程序执行过程中始终占用同一个cpu内核,工作量和所需时间成线性比;在多线程的情况下,程序将任务分配在不同的cpu内核,工作量和所需时间不成线性比。
例子中,method2和method3其实可以看成是要分别完成两个任务(这里是两个相同的任务),在method2中,完成这两个任务是有先后顺序的,且在执行第二个任务的前提是第一个任务已经完成;在method3中,两个任务则是同时开始执行,且它们是独立完成的。method3的做法其实就是典型的“抢先式多任务”的实现,线程t1与t2由系统分配cpu资源和时间片,两个线程开始后,二者互相之间没有影响(仅限在这个例子中,因为线程是共享内存资源的),即不会因为其中一个线程执行的任务繁复而影响另一个线程的执行。但“抢先式多任务”的实现是需要付出更多的系统开销(overhead)的,所以,虽然两个任务分配到两个不同cpu内核,且并发执行,但它还是需要花费比method1更多的时间。这在前文也已经交代过,“抢先式多任务”的盛行,是以成熟的硬件支持为前提的。
我们针对method3,再进一步做一组测试,在这个测试中,我们分别创建1,2,3,4,5,6,7,8条线程,并记录下它们的执行时间和cpu使用情况,代码如下:
1 class Program 2 { 3 4 static void Main(string[] args) 5 { 6 7 Console.Write("Start : "); 8 Console.WriteLine(DateTime.Now.ToLongTimeString()); 9 10 // method 3 11 // multithreads 12 13 14 WasteTime w1 = new WasteTime(); 15 WasteTime w2 = new WasteTime(); 16 //WasteTime w3 = new WasteTime(); 17 //WasteTime w4 = new WasteTime(); 18 //WasteTime w5 = new WasteTime(); 19 //WasteTime w6 = new WasteTime(); 20 //WasteTime w7 = new WasteTime(); 21 //WasteTime w8 = new WasteTime(); 22 23 24 Thread t1 = new Thread(new ThreadStart(w1.run)); 25 Thread t2 = new Thread(new ThreadStart(w2.run)); 26 //Thread t3 = new Thread(new ThreadStart(w3.run)); 27 //Thread t4 = new Thread(new ThreadStart(w4.run)); 28 //Thread t5 = new Thread(new ThreadStart(w5.run)); 29 //Thread t6 = new Thread(new ThreadStart(w6.run)); 30 //Thread t7 = new Thread(new ThreadStart(w7.run)); 31 //Thread t8 = new Thread(new ThreadStart(w8.run)); 32 33 34 t1.Start(); 35 t2.Start(); 36 //t3.Start(); 37 //t4.Start(); 38 //t5.Start(); 39 //t6.Start(); 40 //t7.Start(); 41 //t8.Start(); 42 43 44 45 t1.Join(); 46 t2.Join(); 47 //t3.Join(); 48 //t4.Join(); 49 //t5.Join(); 50 //t6.Join(); 51 //t7.Join(); 52 //t8.Join(); 53 54 Console.Write("Finish : "); 55 Console.WriteLine(DateTime.Now.ToLongTimeString()); 56 Console.ReadKey(); 57 58 } 59 }
测试结果记录如下:
线程数 |
1 |
2 |
3 |
时间 |
13s |
16s |
19s |
Cpu使用率情况 |
|||
线程数 |
4 |
5 |
6 |
时间 |
22s |
28s |
33s |
Cpu使用率情况 |
|||
线程数 |
7 |
8 |
|
时间 |
40s |
46s |
|
Cpu使用率情况 |
注:以上数据在i5 3230m cpu上测试得到,测试过程中仅开启visual studio和资源监视器,图像右侧小部分曲线为开启截图软件导致
由以上数据可以看出:
1、 当线程数不超过cpu内核数时,每增加一条线程,完成任务付出的额外时间较之线程数超过cpu内核数时增加线程数完成任务所需时间更少;
2、 当线程数超过cpu内核数时,程序执行过程中,会有若干间隔时间cpu使用率骤降,且线程数越多,间隔越频繁;
由此可以进一步得出结论:在“抢先式多任务”实现中,尽管线程数超过了cpu内核数,但各线程还是被系统分配到了不同的内核执行;随着线程数量的增加,时间片的分配也变得更频繁,系统内销也随之加大,增加一条线程额外增加的时间也变得更多。
从中我们可以看出,“抢先式多任务”的原则,是要把诸多的任务进行分割,做平行处理,因此也带来了更大的系统开销。因为无论是时间片的分配、任务的挂起和恢复都是需要系统做更多的工作,并且这些工作都是建立在一定的硬件支持上的。
以上是“抢先式多任务”例子的分析,下面举个“协同式多任务”的例子,先看如下代码:
1 interface Runnable 2 { 4 5 void run(); 6 7 }
1 class Cat : Runnable 2 3 { 4 5 public void run() 6 7 { 8 9 Console.WriteLine("I am a cat"); 10 11 } 12 13 }
1 class Cow : Runnable 2 3 { 4 5 public void run() 6 7 { 8 9 Console.WriteLine("I am a cow"); 10 11 } 12 13 }
1 class Dog : Runnable 2 3 { 4 5 6 7 public void run() 8 9 { 10 11 Console.WriteLine("I am a dog"); 12 13 } 14 15 }
1 class WasteTime:Runnable 2 3 { 4 5 public void run() 6 7 { 8 9 int j; 10 11 for (int i = 0; i < 1000000000;i++ ) 12 13 { 14 15 j = i; 16 17 } 18 19 Console.WriteLine("==========This is an interval============="); 20 21 } 22 23 }
1 class Program 2 3 { 4 5 static void Main(string[] args) 6 7 { 8 9 List<Runnable> eventqueue = new List<Runnable>(); 10 11 12 13 eventqueue.Add(new Cat()); 14 15 eventqueue.Add(new Dog()); 16 17 eventqueue.Add(new Cow()); 18 19 eventqueue.Add(new WasteTime()); 20 21 22 23 for (int i = 0; i < 10; i++) 24 25 { 26 27 foreach (Runnable r in eventqueue) 28 29 { 30 31 32 33 r.run(); 34 35 } 36 37 } 38 39 40 41 Console.ReadKey(); 42 43 44 45 } 46 47 }
例子中的代码要做的事,其实就是反复的每隔一段时间运行Cat,Cow,Dog三个类实例的run方法(WasteTime在这里仅仅为了取得时间间隔的效果),三个实例的run方法可以看成三个任务,因为相对于WasteTime间隔的时间,三个实例执行run方法十分迅速,可以看成是同一时间内进行,这就是一个典型的“协同式多任务”的实现——因为当执行Cat的run方法时,只要程序还没跳出该方法的函数体,cpu的使用权就一直掌握在该方法所属任务手中,这里的run方法就相当于主程序的回调函数;同样的道理适用在Cow和Dog中。任务的执行并非由系统做出统筹分配,而是“该到谁就到谁”。假如我们在其中某个run方法体内加入了复杂的代码,使得程序执行长时间不能跳出方法体,这时其他任务将被推迟执行。由于这种有秩序的执行多任务的方式,“协同式多任务”相对于“抢先式多任务”并不需要太大的系统内销,而且其在编码时能使程序员更清晰当前思路,因为这是一种程序“自上而下”的执行方式;但它却要求每个回调函数不能承载太繁重的任务。
由此可见,两种多任务的实现方式各有所长,在可预见的未来,都会在不同的应用场合中发挥作用。
转载于:https://www.cnblogs.com/sengnj/p/3566441.html
“抢先式多任务”“协同式多任务”相关推荐
- X86汇编语言从实模式到保护模式17:协同式任务切换
目录 1. 多任务和任务切换概述 1.1 多任务系统 1.2 任务切换含义 1.2.1 切换任务上下文 1.2.2 上下文是什么 1.3 任务切换方式概述 1.3.1 协同式任务切换 1.3.2 抢占 ...
- RTOS 系统篇-多任务协同与复杂消息的设计
RTOS 系统篇-多任务协同与复杂消息的设计 概述 对嵌入式系统的功能进行"任务划分",是 RTOS 中软件设计的关键.当任务划分比较合理时,整体的软件设计就会比较简洁.高效.容易 ...
- 线程的调度之协同式和抢占式
大家好,我是神韵,是一个技术&生活博主.关于文章都是定位为基础,我不敢讲的太深入,因为我怕自己没时间.欢迎来点赞打卡,你们的行动将是我无限的动力. 今日主题是:线程的调度之协同式和抢占式 话不 ...
- CACC 协同式自适应巡航模型 搭建四辆车在carsim和simulink进行协同式自适应巡航 其中间距策略考虑领航车速的影响,各个车辆采用分层式控制,分层式控制器主要分为下层控制
CACC 协同式自适应巡航模型(仿真软件版本:Carsim2016,Matlab2018b及以上) 搭建四辆车在carsim和simulink进行协同式自适应巡航,其中间距策略考虑领航车速的影响,各个 ...
- CACC 协同式自适应巡航模型 搭建四辆车在carsim和simulink进行协同式自适应巡航
CACC 协同式自适应巡航模型(仿真软件版本:Carsim2016,Matlab2018b及以上) 搭建四辆车在carsim和simulink进行协同式自适应巡航,其中间距策略考虑领航车速的影响,各个 ...
- V2X应用场景之协同式自动驾驶
转自:http://zhidx.com/p/96637.html V2X应用场景之协同式自动驾驶 这个应用场景我觉得是比较典型的,也想多花点时间给大家介绍一下,就是关于V2X在自动驾驶里面很典型的应用 ...
- 直播预告 | 斯坦福助理教授马腾宇:深度学习中的隐式和显式正则化
人工智能作为科技领域最具代表性的技术,日益成为国际竞争的新焦点.当下,我国正逐步开展全民智能教育普及,设置人工智能相关课程,致力于建设人工智能的人才高地. 在此背景下,中关村海华信息技术前沿研究院立足 ...
- Algorithm Gossip (22) 中序式转后序式(前序式)
前言 This Series aritcles are all based on the book <经典算法大全>; 对于该书的所有案例进行一个探究和拓展,并且用python和C++进行 ...
- BC之链式块状结构:区块链之链式块状结构——链式块状结构、内容相关配图
BC之链式块状结构:区块链之链式块状结构--链式块状结构.内容相关配图 目录 区块链之链式块状结构.内容相关配图 1.区块链结构 区块链之链式块状结构.内容相关配图 1.区块链结构
最新文章
- 使用system语句出现不明确问题
- c语言子程序return,c语言return返回到哪
- linux学习笔记-不定时更新
- CRM Fiori launchpad请求响应结果的字段分析
- JS生成随机数并排序
- magisk核心功能模式是什么_科技板块——深入解析MM管理器
- 致敬学长!J20航模遥控器开源项目计划【开局篇】 | 先做一个开机界面 | MATLAB图像二值化 | Img2Lcd图片取模 | OLED显示图片
- 人脸识别接口_人脸识别双目摄像头模组应用系统
- java jmail_JavaMail学习--使用JMail发送邮件
- 删除烦人的微软拼音输入法
- 夜神模拟器连接手柄无反应_夜神安卓模拟器怎样连接手柄 夜神模拟器连接手柄图文教程...
- win7远程桌面连接
- Ruff 将助力广东金融高新区“区块链+”金融科技创新与应用落地
- 【Json转换为实体类】
- 第 三 十 八 天:Apache 选 项 和 模 块 问 题 附:php
- IOS 最新邓白氏编码申请
- jquery中的ajax方法请求后台数据
- 大学计算机excel函数课件,二级计算机考试Excel函数PPT课件
- 二、了解shiro架构 (10 Minute Tutorial on Apache Shiro)
- 《麦肯锡意识》前言 解决问题的战略模型-思维导图
热门文章
- JavaAndroid 基础知识梳理(8) 容器类
- elementUI v-loading不显示问题
- iOS 判断是否安装了微信、QQ客户端
- 如何在 IDEA 中创建并部署 JavaWeb 程序
- 图像修复:Object Removal by Exemplar-Based Inpainting 学习笔记
- [JAVA]从零开始的“桌面宠物”之路(一):动画效果
- FreeNOS-kernel目录下boot.S、链接脚本kernel.ld文件分析(四)
- Sklearn中predict_proba函数用法及原理详解
- 浅谈“戒色”与“慎独”
- 2022长安杯赛后复现