守护线程
两个关键词:守护/线程
守护:伴随,线程:本质也是一种线程
守护线程会随着该进程内的所有非守护线程结束而结束。即,守护线程是守护着整个进程的运行周期
怎么用
和开启守护进程的方式一样,在start()之前设置daemon=True
import time from threading import Thread def foo(name): print('%s is running' % name) # time.sleep(1) time.sleep(3) print('123') def bar(name): print('%s is running' % name) time.sleep(1) print('%s is done' % name) t1 = Thread(target=foo, args=('守护线程',)) t2 = Thread(target=bar, args=('子线程',)) t1.daemon = True t1.start() t2.start() print('主') #运行结果 守护线程 is running 子线程 is running 主 子线程 is done
从运行结果可以看出,守护线程伴随着子进程的结束而结束,并没有运行后面的代码
互斥锁
互斥锁的作用是使多个任务对共享数据的操作由并发变为“串行”,虽然牺牲了效率,但是保证了数据的安全
没有互斥锁的情况下:
import time from threading import Thread, Lock lock_obj = Lock() x = 1000 l = [] def task(): global x temp = x-1 time.sleep(0.1) # 由于起线程的速度太快,要加上这句,模拟多个并发线程对共享数据的修改 x = temp start = time.time() for i in range(300): thread = Thread(target=task) l.append(thread) thread.start() for t in l: t.join() end = time.time() print('主', x, end - start)
有互斥锁的情况下
import time from threading import Thread, Lock lock_obj = Lock() x = 1000 l = [] def task(): global x with lock_obj: temp = x-1 time.sleep(0.01) x = temp start = time.time() for i in range(300): thread = Thread(target=task) l.append(thread) thread.start() for t in l: t.join() end = time.time() print('主', x, end - start)
信号量
控制同一时刻并发执行的任务数
import time, random from threading import Thread, current_thread, Semaphore sm = Semaphore(5) def task(): with sm: print('%s:正在上厕所...' % current_thread().name) time.sleep(random.uniform(1, 3)) print('%s:出厕所' % current_thread().name) if __name__ == '__main__': for i in range(20): obj = Thread(target=task) obj.start()