什么时候用单线程执行器,什么时候用多线程执行器?
-
今天在社区里遇到小伙伴提了这个问题,简单的分享下,顺便把之前关于多线程相关的文章放一下。
ROS2模式用的是单线程执行器,为什么默认单线程,原因是节省资源(线程少),但有时我们需要同时处理多个事情,想要使用单线程实现就不那么方便了。
学习了C语言的小伙伴,接触的最多的是顺序执行,当我们需要某个资源A的时候,我们发送请求,接着等待A资源到位,然后再去请求B资源,然后等待B资源到位,这样做有两个缺点,1是无法实现同时发送AB请求-耽误时间,2是发送之后需要等待资源到位-浪费资源。
先解决第一个问题:耽误时间
那有没有什么办法可以同时获取A资源和B资源呢?答案就是多线程,开两个线程,一个线程请求A,然后线程A等待,另一边一个请求B,然后等待,这样就行了,但是多开一个线程对操作系统的调度来说就会增加一份负担,更造成了资源的浪费。
再解决第二个问题:资源浪费
既然两个线程浪费资源,一个线程怎么实现同时发送请求,且一起等待呢?其实很简单,我们发送完A请求时设置一个回调函数,就是告诉系统,当A资源到位的时候你调用我给的函数,把数据传给我就行了。发送完A之后立马就发送B请求,同样可以设置一个回调函数,因为时间足够短,所以可以近似为同时发送请求,这样一来就实现了单线程的调度(这也是ROS2为什么用那么多回调函数的原因)。
单线程执行器存在什么问题,ROS2为什么还要引入多线程执行器?
单线程执行器的核心是单线程,如果我们的某一个回调函数里出现了堵塞(死循环)就会造成接下来的其他程序无法执行,比如发送A请求卡死,接着就没办法发送B请求了。
上述这种情况一般比较难遇到,我们在ROS2中遇到最多的就是死锁问题,因为默认是单线程调度的,所以当我们想在A的回调函数里等待B资源到位(很多小伙伴会这样做的,有的是在图片处理回调函数里等待订阅图片的回调函数拿到图片再继续往下执行),这种情况就会死锁,原因很简单,我们是单线程的是吧,同一时间只能做一件事,所以当你在
处理回调函数里等待
时那么图片接收的回调就不可能再进入了(接收回调在等处理回调执行完才能执行)。遇到这种死锁问题怎么办,只能开多线程了(其实还可以用协程,在等待的时候把时间片让出去),我们可以开一个单独的线程给处理回调函数,让他自己在一个线程里默默等待,这样就不影响其他回调函数的执行了,再ROS2中实现的方式就是回调组,通过回调组设置,你可以让指定回调函数在哪一个线程进行执行。
不得不服ROS2的这个回调组的设计,当初小鱼看到时也觉得挺不错的设计,后来在公司项目上我们也复现过这一设计,让频率较高的传感器数据在单独的一个线程中执行。
线程开多了有的时候可能还会觉得慢,这个时候可以尝试更换实时内核或绑定CPU等操作。
今天先说到这里,本来要发MicroROS相关,但做的板子还没到,稍微缓缓~
往期文章: