Pyhon线程
多线程注意点
- 如果创建Thread时执行的函数运行结束,意味着该子线程结束。
- 主线程结束,程序结束,主线程会等待子线程结束。
- 子线程的开始是从调用start开始的。
- 线程创建之后谁先执行是不确定的,可以通过添加sleep来指定顺序。
- 查看线程个数使用len(threading.enumerate())
import threading import time def test1(): for i in range(5): print("....test1....%d"%i) time.sleep(1) def test2(): for i in range(8): print("....test2....%d"%i) time.sleep(1) def main(): t1 = threading.Thread(target=test1) t2 = threading.Thread(target=test2) t1.start() t2.start() while True: print(threading.enumerate()) if (len(threading.enumerate())<=1): break time.sleep(1) if __name__ == "__main__": main()
共享全局变量
- 共享全局变量可以方便多个线程共享数据
- args传入一个元组作为参数
- 不可变类型需要global声明,可变类型不需要
import threading import time # 定义一个全局变量 g_num = 100 def test1(temp): temp.append(33) print("in test1 g_num=%s" % str(temp)) def test2(temp): print("in test2 g_num=%s" % str(temp)) g_nums = [11, 22] def main(): # target指定将来哪个线程去哪个函数执行代码 # args指定将来调用函数的参数 t1 = threading.Thread(target=test1, args=(g_nums,)) t2 = threading.Thread(target=test2, args=(g_nums,)) t1.start() time.sleep(1) t2.start() time.sleep(1) print("in main g_num=%s" % str(g_nums)) if __name__ == "__main__": main()
共享全局变量造成资源竞争
- 不同线程都要修改某个变量,比如都要执行g_num+=1,这个过程分为三步:
- 获得g_num的值
- 给这个值加一
- 把加一后的值赋给g_num
- 如果第一个线程执行了前两步,获得g_num=0,然后加一,但还没有赋值给n_num就进入休眠,轮到第二个线程执行,获得的g_num的值还是0,加一后得到1,还没执行第三步,又轮到第一个线程,这时线程1会接着上次的操作,直接从第三步开始,得到g_num=1;再次轮到第二个线程,也接着从第三步开始,得到g_num=1,两个线程结束后本该得到g_num=2,这里确得到1.
- 为了解决上述问题,引入互斥锁的概念,使用threading模块中的Lock,给可能冲突的代码段上锁、解锁。从而避免资源竞争引发的错误。
- 当存在多个锁时,可能存在死锁问题,两个线程都等待对方解锁,程序设计中要尽量避免死锁。
import threading import time # 定义一个全局变量 g_num = 0 def test1(num): global g_num for i in range(num): mutex.acquire() g_num += 1 mutex.release() print("in test1 g_num=%d" % g_num) def test2(num): global g_num for i in range(num): mutex.acquire() g_num += 1 mutex.release() print("in test2 g_num=%d" % g_num) mutex = threading.Lock() def main(): # target指定将来哪个线程去哪个函数执行代码 # args指定将来调用函数的参数 t1 = threading.Thread(target=test1, args=(1000000,)) t2 = threading.Thread(target=test2, args=(1000000,)) t1.start() t2.start() while len(threading.enumerate()) != 1: time.sleep(1) print("in main g_num=%d" % g_num) if __name__ == "__main__": main()