并发:指的是任务数多余cpu核数,通过操作系统的各种任务调度算法,实现用多个任务“一起”执行(实际上总有一些任务不在执行,因为切换任务的速度相当快,看上去一起执行而已)
并行:指的是任务数小于等于cpu核数,即任务真的是一起执行的
线程
python的thread模块是比较底层的模块,python的threading模块是对thread做了一些包装的,可以更加方便的被使用
基本线程调用实例:
import time import threading def dancing(): for i in range(1, 4): print('跳舞中%d' % i) time.sleep(0.5) print('dancing 线程结束') def singing(): for i in range(1, 5): print('唱歌中%d' % i) time.sleep(0.5) print('singing 线程结束') def main(): # 创建子线程对象 t1 = threading.Thread(target=dancing) t2 = threading.Thread(target=singing) # 子线程开始执行 t1.start() t2.start() # 查看正在运行的子线程数量 while True: length = len(threading.enumerate()) print('当前运行的线程数为:%d' % length) if length <= 1: break time.sleep(0.2) if __name__ == '__main__': main()
继承Thread类自定义类调用实例:
import threading import time class DancingThread(threading.Thread): def run(self): for i in range(1, 3): print('线程名:%s,正在跳舞:。。。%d' % (self.name, i)) time.sleep(0.5) print('\n跳舞线程结束') class SingingThread(threading.Thread): def run(self): for i in range(1, 5): print('线程名:%s,正在唱歌:。。。%d' % (self.name, i)) time.sleep(0.5) print('唱歌线程结束') def main(): # 创建Thread对象 dancing = DancingThread() sing = SingingThread() # 调用run方法,开启线程 dancing.start() sing.start() if __name__ == '__main__': main()
线程共享全局变量
- 在一个进程内的所有线程共享全局变量,很方便在多个线程间共享数据
- 缺点就是,线程是对全局变量随意遂改可能造成多线程之间对全局变量的混乱(即线程非安全)
- 假设两个线程t1和t2都要对全局变量g_num(默认是0)进行加1运算,t1和t2都各对g_num加10次,g_num的最终的结果应该为20。
- 但是由于是多线程同时操作,有可能出现下面情况:
-
- 在g_num=0时,t1取得g_num=0。此时系统把t1调度为”sleeping”状态,把t2转换为”running”状态,t2也获得g_num=0
- 然后t2对得到的值进行加1并赋给g_num,使得g_num=1
- 然后系统又把t2调度为”sleeping”,把t1转为”running”。线程t1又把它之前得到的0加1后赋值给g_num。
- 这样导致虽然t1和t2都对g_num加1,但结果仍然是g_num=1
import threading import time g_num = 0 class DancingThread(threading.Thread): def __init__(self, num): threading.Thread.__init__(self) self.num = num def run(self): global g_num for i in range(self.num): g_num += 1 print('跳舞线程结束,g_num:%d' % g_num) class SingingThread(threading.Thread): def __init__(self, num): threading.Thread.__init__(self) self.num = num def run(self): global g_num for i in range(self.num): g_num += 1 print('唱歌线程结束,g_num:%d' % g_num) def main(): # 创建Thread对象 dancing = DancingThread(1000000) sing = SingingThread(1000000) # 调用run方法,开启线程 print('初始g_num: %d' % g_num) dancing.start() sing.start() # 等待子线程运行完 while len(threading.enumerate()) > 1: time.sleep(1) print('线程结束后g_num: %d' % g_num) if __name__ == '__main__': main()
运行结果为:
初始g_num: 0 跳舞线程结束,g_num:1292807 唱歌线程结束,g_num:1712212 线程结束后g_num: 1712212
使用互斥锁解决线程冲突
# 创建锁 mutex = threading.Lock() # 锁定 mutex.acquire() # 释放 mutex.release()
import time import threading g_num = 0 def dancing(num, mutex): global g_num for i in range(num): # 上锁 mutex.acquire() # 计算 g_num += num # 解锁 mutex.release() print('dancing 线程结束,num值: %d' % g_num) def singing(num, mutex): global g_num for i in range(num): # 上锁 mutex.acquire() # 计算 g_num += num # 解锁 mutex.release() print('dancing 线程结束,num值: %d' % g_num) def main(): print('初始值:%d' % g_num) # 创建锁对象 mutex = threading.Lock() # 创建子线程对象 t1 = threading.Thread(target=dancing, args=(1000000, mutex, )) t2 = threading.Thread(target=singing, args=(1000000, mutex, )) # 子线程开始执行 t1.start() t2.start() if __name__ == '__main__': main()
运行结果:
初始值:0 dancing 线程结束,num值: 1876392000000 dancing 线程结束,num值: 2000000000000