目录
第十五章、并发编程之线程
1.什么是线程
纠正概念:进程其实不是个执行单位,进程是一个资源单位,每个进程内自带一个线程,线程才是cpu上的执行单位
抽象理解:
进程是指在系统中正在运行的一个应用程序;线程是系统分配处理器时间资源的基本单元,或者说进程之内独立执行的一个单元。对于操作系统而言,其调度单元是线程。
线程:cpu最小的执行单位进程:资源集合/资源单位.线程运行 = 运行代码进程运行 = 各种资源 + 线程
图片理解:
例子理解:
在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程在工厂中, 每个车间都有房子,而且每个车间默认就有一条流水线.
2. 进程和线程的区别
线程:单个线程的内存空间数据共享(进程内的数据)
进程:物理内存空间隔离(多个进程内存空间彼此隔离)
进程是告诉操作系统开辟内存空间
线程是告诉操作系统执行一条任务代码(线程的创建速度是进程的100倍)
3. 开启线程的两种方式
函数开启
from threading import Threadimport timedef task(name): print('%s is runing '%name) time.sleep(2) print('%s is done'%name) t=Thread(target=task,args=('子线程',))t.start()
类开启
class Task(Thread): def run(self): print('%s is runing ' % self.name) time.sleep(2) print('%s is done' % self.name)t = Task()t.start()print('zhu')
4.子线程与子进程创建速度
from threading import Threadfrom multiprocessing import Processimport timedef task(name): print(f'{name} is running') time.sleep(2) print(f'{name} is end')if __name__ == '__main__': t = Thread(target=task,args=('子线程',)) p = Process(target=task,args=('子进程',)) # t.start() p.start() print('主')------------------------------------------------############开启子线程的打印效果:################子线程 is running主子线程 is end##########开启子进程打印效果:##################主子进程 is running子进程 is end
总结:线程比进程创建速度快
5.子线程共享数据的证明
from threading import Threadimport time,osx = 100def task(): global x x = 50 print(os.getpid()) # 4652 if __name__ == '__main__': t = Thread(target=task) t.start() time.sleep(2) print(x) # 50 print(os.getpid()) # 4652------------------------------------------4652504652
进程开启子进程是开辟新的内存空间,而线程开启子线程是共用一个内存空间
即:进程开启子进程的pid号不一样,
线程开启子线程的pid号一样
6.线程的join方法
单个子线程
子线程 start主线程子线程 endfrom threading import Threadimport timedef task(): print('子线程 start') time.sleep(2) print('子线程 end')def task2(): print('子线程 start') time.sleep(5) print('子线程 end')t = Thread(target=task)t.start()t2.start()t.join() # 等待子线程运行结束print('主线程')-------------------------------子线程 start子线程 end主线程----------------------------------#给t.join()加注释的结果如下子线程 start主线程子线程 end
说明:主线程将会等待子线程的sleep和这样的一段时间,子线程的start()在join之前,说明该子线程必须运行结束,才运行到print('主线程')
,主线程才执行完毕,如果给t.join()加注释,则说明主线程执行完毕了后,主线程直接结束。
多个子线程
from threading import Threadimport timedef task(name,n): print(f'{name} start') time.sleep(n) print(f'{name} end')t1 = Thread(target=task,args=('线程1',1))t2 = Thread(target=task,args=('线程2',2))t3 = Thread(target=task,args=('线程3',3))start = time.time()t1.start()t2.start()t3.start()t1.join() # 111st2.join() #t3.join()end = time.time()------------------------------------------线程1 start线程2 start线程3 start线程1 end线程2 end线程3 end3.0022878646850586#主线程开始->线程1开始->线程1结束->线程2开始->线程2结束->线程3开始->线程3结束->主线程结束#因为1线程、2线程、3线程进入了同一个方法,本应该"同时"start()运行,但是现在是线程1 在start后使用join,那么线程2会老老实实的等线程1先跑完
说明:实现了多线程的并发执行
思考
思考一下 在单核的情况下 多个线程是如何利用cpu的?
答:单核CPU上运行的多线程程序, 同一时间只能一个线程在跑, 系统帮你切换线程而已, 系统给每个线程分配时间片来执行, 每个时间片大概10ms左右, 看起来像是同时跑, 但实际上是每个线程跑一点点就换到其它线程继续跑效率不会有提高的 切换线程反倒会增加开销
7.了解进程的join
from multiprocessing import Processfrom threading import Threadimport timedef task(): print('进程 开启') time.sleep(10) print('进程 结束')def task2(): print('子线程 开启') time.sleep(2) print('子线程 结束')if __name__ == '__main__': p = Process(target=task) t = Thread(target=task2) t.start() # 开线程 p.start() # 开进程 print('子进程join开始') p.join() # 主进程的主线程等待子进程运行结束 print('主')
8. 线程的其他相关用法
# print(t1.is_alive()) # True # print(t1.getName()) # Thread-1 # print(t2.getName()) # Thread-2 # t1.setName('班长') # print(t1.getName()) # print(currentThread().name) # print(enumerate()) # [<_MainThread(MainThread, started 1856)>,, ] # print(activeCount()) # 3 # print(len(enumerate())) # 3