前言
感觉理解python多线程用“切换”和“共享”就差不多了。这里就贴上一个抢车票的小小实例,还有自己在编程过程中遇到的坑.....
实例:抢车票
抢车票有三类人:会员、弄了加速包、普通人。
说说区别:
钱带来的不公平:会员先跑,然后加速包,最后普通人
可以欣慰的公平:跑道一样长
守护线程SetDaemon
不设置守护进程
1 import threading 2 import time 3 #使用函数式 4 5 #会员 6 def vip(t1): 7 global num 8 time.sleep(2) #等待时间相同,区别是进场的先后顺寻 9 if num == 15: 10 print("用时:", time.time() - t1) 11 exit(0) 12 num += 1 13 print('会员,当前被抢票数:', num) 14 #有加速包的家伙 15 def aboostOne(t1): 16 global num 17 time.sleep(2) #等待时间相同,区别是进场的先后顺寻 18 if num == 15: 19 print("用时:",time.time()-t1) 20 exit(0) 21 num+=1 22 print('加速包,当前被抢票数:', num) 23 24 #没有加速包的苦逼 25 def commonOne(t1): 26 global num 27 time.sleep(2) #等待时间相同,区别是进场的先后顺寻 28 if num == 15: 29 print("用时:", time.time() - t1) 30 exit(0) 31 num += 1 32 print('苦逼青年,当前被抢票数:', num) 33 34 if __name__ =='__main__': 35 t1 =time.time() #开始时间 36 num =0 #只有15张票 37 #vip优先,来3个 38 for i in range(3): 39 threading.Thread(target=vip,args=(t1,)).start() 40 #加速包其次,来7个 41 for i in range(7): 42 threading.Thread(target=aboostOne,args=(t1,)).start() 43 #苦逼青年最后,来10个 44 for i in range(10): 45 threading.Thread(target=commonOne,args=(t1,)).start()
结论:
1.加速包可以抢的比会员卡 === 多线程不一定按顺序进行
2.最终打出了5个用时 === 一个线程exit()之后,其他线程不受影响,继续运行
再看看设置守护
其他代码不变,只给苦逼青年daemon.图中有两种方式
结果:
苦逼青年抢票被中断,抛出异常 === 设置守护意味着不重要,主线程退出,守护进程随即被中断
join()设置阻塞
在setDaemon的情况下join,只测试苦逼青年的
结果:
完美运行完了 === join的作用:被join的子线程执行完之后,主线程才能进行。
这里就算SetDaemon,主线程也带等苦逼青年运行完。SetDaemon后,用join,相当于没有设置守护进程
作用:当你想做完一些事,再做另一些事,就可以join一下
遇到的坑
pymysql.err.InternalError: Packet sequence number wrong - got 45 expected 0
原因:
使用了多线程,多线程共享了同一个数据库连接,但每个execute前没有加上互斥锁
方法:
方法一:每个execute前加上互斥锁
lock.acquire()
cursor.execute(command,data)
lock.release()
方法二:
每个线程拥有自己的数据库连接,即在线程调用函数中加上数据库连接代码
方法三:
所有线程共用一个连接池,需要考虑线程总数和连接池连接数上限的问题
另外
threading.Thread(target =,args=(,))
args应当传入Tuble(元组)
第二:传入的参数不是引用传递,而是新分配了内存。估计是把参数初始化到类的成员里面去了吧