多线程注意点
- 如果创建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()