5-[多线程]-线程理论
1、什么是线程
在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程 进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合) 线程才是cpu上的执行单位。
多线程(即多个控制线程)的概念是,在一个进程中存在多个线程,多个线程共享该进程的地址空间,
相当于一个车间内有多条流水线,都共用一个车间的资源。例如,北京地铁与上海地铁是不同的进程,
而北京地铁里的13号线是一个线程,北京地铁所有的线路共享北京地铁所有的资源,比如所有的乘客可以被所有线路拉。
2、多线程应用举例
3、开启进程的两种方式:threading模块
- multiprocess模块的完全模仿了threading模块的接口,二者在使用层面,有很大的相似性,因而不再详细介绍
(1)方法1:thread函数调用
(2)通过继承Thread类进行调用
python包,threading模块中,如何调用的?
调用start()方法,start方法会逐渐调用run()方法
4、线程与进程的区别
- Threads share the address space of the process that created it; processes have their own address space.
- Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process.
- Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes.
- New threads are easily created; new processes require duplication of the parent process.
- Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes.
- Changes to the main thread (cancellation, priority change, etc.) may affect the behavior of the other threads of the process; changes to the parent process does not affect child processes.
(1) 开进程的开销远远大于开线程
执行结果如下,p.start ()将开启进程的信号发给操作系统后,操作系统要申请内存空间,让好拷贝父进程地址空间到子进程,开销远大于线程
执行结果如下,几乎是t.start ()的同时就将线程开启了,然后先打印出了hello,证明线程的创建开销极小
(2)同一个进程的多个线程共享该进程的地址空间
进程之间地址空间是隔离的 执行结果如下,毫无疑问子进程p已经将自己的全局的n改成了0,但改的仅仅是它自己的,查看父进程的n仍然为100
同一进程内开启的多个线程是共享该进程地址空间的 执行结果如下, 查看结果为0,因为同一进程内的线程之间共享进程内的数据
(3)查看pid:
开多个进程,每个进程都有不同的pid
from multiprocessing import Process, current_process 导入模块 current_process().pid 查看进程id
在主进程下开启多个线程,每个线程都跟主进程的pid一样
current_process().pid:也可查看线程的id,不能查看父id os.getpid() 查看进程/线程id os.getppid() 查看进程/线程的父id
5、Thread对象的其他属性或方法
Thread实例对象的方法 # isAlive(): 返回线程是否活动的。 # getName(): 返回线程名。 # setName(): 设置线程名。 threading模块提供的一些方法: # threading.currentThread(): 返回当前的线程变量。 # threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。 # threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
(1)currnet.Thread.getName() 当前线程名称
from threading import Thread, currentThread import time def task(): print('%s is running' % currentThread().getName()) time.sleep(1) print('%s is done' % currentThread().getName()) # 返回当前线程名称 if __name__ == '__main__': t = Thread(target=task) t.start() print(t.getName()) # 线程名:Thread-1 print('当前线程名称', currentThread().getName())
(2)自定义线程名称
(3)isAlive() / is_alive()
(4)查看活动中的线程数量
(5)正在运行线程list
6、守护线程
无论是进程还是线程,都遵循:守护xxx会等待主xxx运行完毕后被销毁
# 详细解释: 1、主进程在其代码结束后就已经算运行完毕了(守护进程在此时就被回收),然后主进程会一直等非守护的子进程都运行完毕后回收子进程的资源(否则会产生僵尸进程),才会结束, 2、主线程在其他非守护线程运行完毕后才算运行完毕(守护线程在此时就被回收)。因为主线程的结束意味着进程的结束,进程整体的资源都将被回收,而进程必须保证非守护线程都运行完毕后才能结束。
7、一般方法,join方法,守护线程对比