进程和线程
来源:互联网 发布:playclub捏脸数据论坛 编辑:程序博客网 时间:2024/05/17 00:18
概念
- 进程:程序运行的状态就是进程。进程包括三个部分:程序(一堆代码)、数据集(程序在执行过程中的所有数据的集合)、进程控制块PCB(寄存器保存状态,OS利用它来管理进程)
- 线程:在现代操作系统中,进程相当于一个容器,线程是其中的执行单位。线程具有三种状态:运行态,阻塞态,就绪态。
- 二者的关系:
- 一个线程只能属于一个进程,一个进程至少有一个线程。
- 进程都是最小的资源管理单元,线程是最小的执行单元:即操作系统分配资源给进程,同一进程的所有线程共享进程的资源;操作系统分配线程给CPU执行。例如:运行一个.py文件就是一个进程(只不过只有一个线程)。这个文件是由python解释器执行的,所以在任务管理器中看到的是python.exe (通过sleep或input阻塞让其保持运行才能查看)
- 串行、并行、并发:
- 串行:执行完一个线程,再执行下一个。串行并不意味着效率低:纯计算的任务,串行执行并没有效率问题;如果是IO密集型任务,串行执行效率极低。
- 并行:同时执行多个进程/线程,需要多核CPU,由系统调配。
- 并发:同一时间段内,多个线程在同一CPU上切换运行。比如:比如,如果有2个线程,两个cpu, 那么就是并行。如果有4个线程,两个cpu, 那么就是并行加并发。
- 并发/并行的问题:开进程和线程有资源开销,不能无限制开启。解决方案:进程池/线程池,将进程或线程控制在一定数量内(计算机可承受的范围),但是池的大小需要根据任务规模的增大而调高,如果任务数过多,池的效率也有问题。
- 进程/线程的切换原则:由OS控制的
- 时间片
- 遇到I/O操作:比如sleep, input, socket.recv, socket.accept
- 优先级切换
- 任务的调用方式:同步和异步:
- 同步:一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么该进程将会一直等下去,直到收到返回信息才继续执行下去。
- 异步:异步常和回调函数捆绑在一起。主进程提交完任务后,不需要等待子进程返回结果,而是继续执行下面的操作,一旦子进程返回了结果,系统会通知主进程进行处理(触发回调函数的执行),这样提高执行的效率。
GIL和python中的线程
Python代码的执行由python虚拟机(CPython)来控制。CPython中的GIL全局解释器锁,控制同一时刻同一进程中只能有一个线程被执行。
无法实现一个进程内多线程的并行,浪费了多核的优势。
因此同一进程中,Python的多线程是并发的。并发的切换机制,决定了python的多线程适合I/O密集型的程序,而对于计算密集型的程序,反而可能会降低程序性能。举个栗子:
I/O密集型:
import threadingimport timeprint('主线程开始:',time.ctime())def foo(n): print('>>>>> run foo',n) time.sleep(3) print('end foo',n)ts = []for i in range(3): t= threading.Thread(target=foo, args=(i,)) #实例化线程对象 ts.append(t) #添加线程列表中for t in ts: t.start() # 执行子线程for i in ts: t.join() # 主线程等待子线程结束再执行print('主线程结束:',time.ctime())'''执行结果一共是3秒。如果不利用多线程,结果将是9秒。主线程开始: Mon Jul 17 15:53:56 2017>>>>> run foo 0>>>>> run foo 1>>>>> run foo 2end foo 1end foo 0end foo 2主线程结束: Mon Jul 17 15:53:59 2017'''
计算密集型开多线程,python一次只能运行一个线程,由于没有I/O阻塞,时间片到了后,就会切换线程,这样反复切换反而比单线程模式花费了更多时间。
threading模块
产生子线程对象(子线程可以再开子线程)
t = threading.Tread(target=func, args=(元组))
threading.active_count() 当前进程中活动线程的数量(如果一个线程t t.join() 结束后,那么t不计入数量。)
threading.enumerate() 查看正在运行的线程的清单
Thread()对象的函数
t.start() # 运行子线程
t.run() # 定义线程的功能的函数,一般会被子类重写。
t.join(timeout=None) # 主程序挂起,等待子线程结束
t.setDaemon(True) # 设置为守护线程。在threading中,主线程执行完后,会等待子线程结束,然后退出。设置了Daemeon后(相当于线程不重要),主进程执行完后,无论子线程是否结束,全部结束,程序退出。子进程的daemon值默认继承创建该线程的值。一般主线程的daemon值默认是False.
通过派生Thread类来实例化化线程线程
import threadingimport time, randomclass MyThread(threading.Thread): # 继承Thread类 def __init__(self,name): # 重用父进程的构造器 super().__init__() self.name=name # 这个要写在父类的构造器方法下下面, # 否则父类的self.name=MyThread-1(会覆盖自己 的self.name属性。 def run(self): # 重写run方法 '''具体的功能函数''' print('[%s] start to runing'% self.name) time.sleep(random.random()) print('[%s] end'% self.name)t = MyThread('test') #实例化线程对象t.start()'''[test] start to runing[test] end'''
重写的类就将函数封装进去了,实例化线程对象obj,通过obj.start()就会调用run方法。
但是大师说了,更推荐用传统的方式,具体原因不明(· - ·):
def func():
pass
t = threading.Thread(target=func, args=(元组)),然后t.start()
- 进程和线程
- 关于进程和线程
- 进程和线程
- 进程和线程
- 小解进程和线程
- 进程和线程
- 理解进程和线程
- 进程和线程
- 进程和线程
- 进程和线程 编程
- 进程和线程
- 进程和线程
- 线程和进程
- 进程和线程编程
- 程序、进程和线程
- 进程和线程 区别
- 进程和线程编程
- 什么是线程和进程
- 解决hostsplus无法安装的问题
- mosquitto的鉴权配置
- Linux下搭建Jenkins+Github环境
- 微软之意不在Xbox,而在于将VR AR引入Win 10
- sql leetcode 627. Swap Salary
- 进程和线程
- Android商城购物车页面实现和逻辑实现
- HDU1595 find the longest of the shortest(dijk+路径记录+枚举)
- 记录一下Struts学习过程中遇到的问题
- Android Studio报错Error:Server sent an unsupported extension: type_35/下载依赖失败/gradle resolve dependenci
- 从网络获取数据,并绑定到listview上
- java eclipse的左侧目录栏不见了
- iOS基石 —— 不常用的基础控件
- 好的前端界面