python threading多线程实例

感知项目需要在sort中夹杂其他任务,跟踪结点的消息发送频率在15Hz以上,如果采用单线程的话会大大拖累sort的速度,因此采用 threading 实现双线程,本贴用一个例子来简述该过程。直接上代码:

import rospy
import threading
import time

'''
job()是子任务,
在主任务中一直循环检测,
当子任务的任务队列有任务时就执行
'''
def job():
    while True:
        if len(tasks)>0:
        	# 线程锁加锁
            lock1.acquire()
            # 修改共享变量
            id = tasks.pop(0)
            # 解除线程锁
            lock1.release()
            print(50*'-')
            print(id)
            print(tasks)
        	# 休眠1s,用来模拟子任务的计算耗时
        	time.sleep(1)
       	# 休眠,防止一直循环占用计算资源,也可不加  
        time.sleep(0.02)

def main():
	# 启动结点,模拟sort跟踪结点
    rospy.init_node('init', anonymous=True)
    rate = rospy.Rate(15)
    # lock是线程锁,防止一个线程在使用共享变量时被另一个线程更改
    global lock1
    lock1 = threading.Lock()
    # 另一个线程,用来做子任务
    thread1 = threading.Thread(target = job)
    # tasks用来表示子任务队列,任务可以是车牌识别等等
    global tasks
    tasks = []
    # k没啥用,只是控制一下循环次数,防止打印太多
    k = 0
    while k<4:
    	# 主任务
    	'''
    	主任务模拟sort.update,
    	当满足要求时,
    	将其添加到任务队列
    	'''
        for i in range(21):
            if i%5==0:
				# 线程锁加锁
                lock1.acquire()
                # 修改共享变量
                tasks.append(i)
                # 解除线程锁
                lock1.release()
        if k<=0:
        	# 只启动一次,实际使用过程中需要设计一下启动条件
            thread1.start()
        # 打印结果
        rospy.loginfo(tasks)
        k += 1
        rate.sleep()

if __name__ == '__main__':
    
    main()
    

打印结果如下:

zxc@zxc-MSI:~/catkin_ws$ rosrun plumbing_server_client test.py 
--------------------------------------------------
[INFO] [1664782453.415831]: [5, 10, 15, 20]
0
[5, 10, 15, 20]
[INFO] [1664782453.482819]: [5, 10, 15, 20, 0, 5, 10, 15, 20]
[INFO] [1664782453.549604]: [5, 10, 15, 20, 0, 5, 10, 15, 20, 0, 5, 10, 15, 20]
[INFO] [1664782453.616296]: [5, 10, 15, 20, 0, 5, 10, 15, 20, 0, 5, 10, 15, 20, 0, 5, 10, 15, 20]
--------------------------------------------------
5
[10, 15, 20, 0, 5, 10, 15, 20, 0, 5, 10, 15, 20, 0, 5, 10, 15, 20]
--------------------------------------------------
10
[15, 20, 0, 5, 10, 15, 20, 0, 5, 10, 15, 20, 0, 5, 10, 15, 20]
--------------------------------------------------
15
[20, 0, 5, 10, 15, 20, 0, 5, 10, 15, 20, 0, 5, 10, 15, 20]
--------------------------------------------------
20
[0, 5, 10, 15, 20, 0, 5, 10, 15, 20, 0, 5, 10, 15, 20]
--------------------------------------------------
0
[5, 10, 15, 20, 0, 5, 10, 15, 20, 0, 5, 10, 15, 20]
--------------------------------------------------
5
[10, 15, 20, 0, 5, 10, 15, 20, 0, 5, 10, 15, 20]
--------------------------------------------------
10
[15, 20, 0, 5, 10, 15, 20, 0, 5, 10, 15, 20]
--------------------------------------------------
15
[20, 0, 5, 10, 15, 20, 0, 5, 10, 15, 20]
--------------------------------------------------
20
[0, 5, 10, 15, 20, 0, 5, 10, 15, 20]
--------------------------------------------------
0
[5, 10, 15, 20, 0, 5, 10, 15, 20]
--------------------------------------------------
5
[10, 15, 20, 0, 5, 10, 15, 20]
--------------------------------------------------
10
[15, 20, 0, 5, 10, 15, 20]
--------------------------------------------------
15
[20, 0, 5, 10, 15, 20]
--------------------------------------------------
20
[0, 5, 10, 15, 20]
--------------------------------------------------
0
[5, 10, 15, 20]
--------------------------------------------------
5
[10, 15, 20]
--------------------------------------------------
10
[15, 20]
--------------------------------------------------
15
[20]
--------------------------------------------------
20
[]

主任务是从0-20遍历,当i是5的倍数时加入任务队列,此时子任务检测到任务队列并行执行任务。从结果来看,由于主任务的频率更高,因此很快执行完,子任务在之后会继续执行。

线程锁是为了防止各个线程同时修改内存,使得结果发生异常,因此在对共享变量进行操作时需要加锁,此时有且只有一个加锁的线程有权对内存进行修改,其他线程都被阻塞。

简单地说,各线程除了在线程锁加锁时是串行执行,其他时间都是并行执行。

参考

多线程解决rospy.spin()语句之后,程序不再往下执行问题

Python Lock acquire()实例讲解

你可能感兴趣的:(经验教训,Ros,python)