多线程编程:
线程:每一个进程都会有一个主线程,先有进程,后有线程。线程是CPU调度的基本单位。
主进程 > 子进程 > 主线程 > 子线程 > 主协程 > 子协程
代码结构和进程一般无二。
代码示例:
import threading
import time
def dance():
for i in range(5):
print(f"跳舞{i}", threading.current_thread())
time.sleep(1)
def sing():
for i in range(5):
print(f"唱歌{i}")
time.sleep(1)
if __name__ == "__main__":
print("这是主线程")
dance_thr = threading.Thread(target=dance, name="my_dance")
sing_thr = threading.Thread(target=sing, name="my_sing")
dance_thr.start()
sing_thr.start()
dance_thr.join()
sing_thr.join()
print("主线程结束")
线程注意事项:
1. 线程执行时无序的
2. 线程之间共享全局变量
3. 线程之间共享全局变量存在资源竞争,当数据量特别大(1000000)的时候,会令数据错乱。 解决方法:线程.join(), 互斥锁。
4. 设置线程守护主线程:如果有多个线程或进程,要每个都守护。
4.1 线程.setDaemon()
4.2 线程.deamon = True
4.3 work2_thr = threading.Thread(target=work2, daemon=True)
关于资源竞争问题:
示例代码:
# 读者运行后,会发现每次结果都不一样。是因为他们都去抢num这个全局变量,所以最终导致数据错乱
import threading
num = 0
def work1():
global num
for i in range(1000000):
num += i
print(num)
def work2():
global num
for i in range(1000000):
num += i
print(num)
if __name__ == '__main__':
work1_thr = threading.Thread(target=work1)
work2_thr = threading.Thread(target=work2)
work1_thr.start()
work2_thr.start()
以上问题有两种解决方案:互斥锁,调用子线程.join()方法
(1)调用join()方法:代码如下
if __name__ == '__main__':
work1_thr = threading.Thread(target=work1)
work2_thr = threading.Thread(target=work2)
work1_thr.start()
work1_thr.join() # 调用子线程.join()方法
work2_thr.start()
(2)互斥锁方法解决资源竞争问题
互斥锁作用:保证同一时间段只有一个线程在操作全局变量
1.创建锁
lock = threaing.Lock()
2.上锁
lock.acquire() # 用在使用全局变量前
代码
3.释放锁
lock.release()
4. 设置线程守护主线程
方法一:
if __name__ == '__main__':
work1_thr = threading.Thread(target=work1)
work2_thr = threading.Thread(target=work2)
work1_thr.daemon = True
work2_thr.daemon = True
work1_thr.start()
work2_thr.start()
print("主线程结束")
方法二:
if __name__ == '__main__':
work1_thr = threading.Thread(target=work1)
work2_thr = threading.Thread(target=work2)
work1_thr.setDaemon(True)
work2_thr.setDaemon(True)
work1_thr.start()
work2_thr.start()
print("主线程结束")
方法三:
if __name__ == '__main__':
work1_thr = threading.Thread(target=work1, daemon=True)
work2_thr = threading.Thread(target=work2, daemon=True)
work1_thr.start()
work2_thr.start()
print("主线程结束")
线程和进程的对比:
关系对比:
1.先有进程,后有线程
2.一个进程肯定有一个对比,也可以创建多个线程
区别对比:
1.进程之间不共享全局变量
2.线程之间共享全局变量,出现资源竞争问题,采用互锁锁或线程同步
3.创建进程的资源开销要比创建线程大
4.进程是操作系统资源分配的基本单位,线程是CPU分配资源的基本单位
5.线程不能够独立运行,必须依存在进程中
6.多进程开发比单进程多线程开发稳定性要强
优缺点对比:
进程优缺点:
优点:可以使用多核。
缺点:资源开销大
线程优缺点:
优点:资源开销小
缺点:不能使用多核