当前位置: 首页 > 科技观察

只有了解了LinuxI-O机制,你才能真正了解“什么是多线程”

时间:2023-03-22 17:07:37 科技观察

你真的了解多线程吗?如果问你“为什么多线程可以提高程序运行的效率?”,你一定会说“计算机并行执行任务,当然是高效!”这显然不是专家应该给出的答案。要知道,一个CPU在任何时间点只能做一件事。如果指令A被执行,则指令B不能被执行。如何并行化?要想真正了解多线程,首先要了解Linux。输入/输出机制。什么是LinuxI/O?一般指文件读写、网卡读写。无论是文件I/O还是网卡I/O,准备数据的速度都远低于CPU处理数据的速度。磁盘读取数据,毫秒级,最慢。其次是网卡,微秒。然后是内存,纳秒级,最快的是缓存。下图是一个Linux进程(只有一个主线程)的执行过程:用户进程向CPU发起读请求,CPU向DMA发起I/O请求,DMA发起I/O请求到磁盘。这里的DMA全称是DirectMemoryAccess,可以简单理解为CPU内存和磁盘之间的代理。磁盘向CPU发起I/O中断,CPU拷贝数据,先拷贝到内核态缓冲区,再拷贝到用户态缓冲区。用户进程从内核态切换回用户态,阻塞态结束,程序继续执行直到结束。在上面的过程中,用户进程在拿到磁盘数据之前只能原地等待,也就是处于阻塞状态。此时CPU处于空闲状态,显然造成了CPU资源的浪费。这时候,如果进程中拉起另一个线程T,那么T就可以利用间隙,在主线程等待数据的时候利用CPU的空闲资源。岂不美哉!这就是多线程技术的由来。总有一些概念让人头晕目眩——同步/异步,阻塞/非阻塞。在学习多线程技术的过程中,总会不时冒出一些概念,比如同步/异步,阻塞/非阻塞。如果你是并发领域的高手,那么这些都是小儿科。如果您是初学者,您很可能会陷入困境并最终放弃。接下来,我们尝试结束这个问题,带你走出这个坑。例如:如果有一天你要去银行办理某项业务,当你到达银行时,你首先需要用你的身份证取一个号码。取号后发现当天人太多,只好等叫号。在等待过程中,你可以有以下选择:选项一:什么都不做,盯着银行液晶屏,当你的号码出现时,起身直奔柜台,银行呼叫号码系统连我都还没来得及拨通你的号码呢。那么,这段时间,你处于阻塞状态,你和银行呼叫系统之间的关系是同步的。“阻塞”很好理解,因为你什么都不做!如何理解“同步”?因为您必须与银行的号码呼叫系统保持同步。当您的号码出现在显示屏上时,您必须立即前往柜台。您无需具备银行自动广播呼叫您办理业务的功能。选项2:您仍然什么都不做,但您坐在座位上开始冥想、做白日梦。因为你知道轮到你的时候,银行呼叫系统会广播呼叫你。听到广播后,起身前往柜台也不迟。那么这段时间,你还是处于阻塞状态。而你和银行呼叫系统之间的关系是异步的,因为你不再需要关注屏幕上滚动的数字。轮到你的时候,它自然会广播告诉你。选择三:对于一个聪明人来说,显然他不会坐以待毙或胡思乱想。这时,你拿起手机,决定玩王者荣耀。游戏过程中,你还是时不时瞥一眼显示屏,看到自己的号码,立马起身前往柜台。那么这段时间你是处于非阻塞状态,因为你在做其他的事情。但是你和银行呼叫系统之间的关系仍然是同步的。选择4:如果你打算专心玩一局王者荣耀,不想坑队友。然后你就等着收音机给你打电话。那么这段时间你是非阻塞状态,和银行调用系统的关系还是异步的。嗯,总结一下:所谓阻塞就是当请求者发起函数调用读取数据时,当数据还没有准备好时,如果函数一直在等待返回结果,就是阻塞;否则,如果函数立即返回,继续执行后面的Actions是非阻塞的。在I/O模型中,如果请求者需要参与从发起请求到最终准备好数据的过程,那么这就称为同步请求;反之,如果应用发送指令,不再参与流程,只需要等待最终完成结果的通知,那么这就是异步的。啊对。上面的方案2也可以认为是方案4,因为你只需要等着银行给你打电话,白日做梦也可以认为是自己做自己的事情!让我们谈谈多线程。所谓多线程就是多个线程同时运行在一个进程中,它们可以处于合作关系,共同完成一项共同的任务,也可以各自做自己的事情。不管是一起工作还是单独工作,总有一个问题是绕不开的:“如何分配CPU资源?”多个线程之间争夺资源的过程可以看成是“零和游戏”。如果线程A抢到的资源多,那么线程A获得的资源B一定少!一般来说,用户只关心CPU的总利用率,数值越大越好,而不是关注每个线程获得的计算资源的多少。