Day 29 process&thread_1
进程和线程 1
进程(process):
1、定义:
最小的执行单元。进程就是一个程序在一个数据集上的一次动态执行过程。
进程一般由程序、数据集、进程控制块三部分组成:
我们编写的程序用来描述进程要完成哪些功能以及如何完成;
数据集则是程序在执行过程中所需要使用的资源;
进程控制块用来记录进程的外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系统感知进程存在的唯一标志。
线程(thread):
1、定义:
最小的资源管理单元。线程的出现是为了降低上下文切换的消耗,提高系统的并发性,并突破一个进程只能干一样事的缺陷,使到进程内并发成为可能。
线程也叫轻量级进程,它是一个基本的CPU执行单元,也是程序执行过程中的最小单元,由线程ID、程序计数器、寄存器集合和堆栈共同组成。
线程的引入减小了程序并发执行时的开销,提高了操作系统的并发性能。线程没有自己的系统资源。
2、进程与线程的关系:
进程(process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
或者说进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。
线程(thread)则是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。
2.1 一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
2.2 资源分配给进程,同一进程的所有线程共享该进程的所有资源。
2.3 CPU分给线程,即真正在CPU上运行的是线程。
3、串行、并行和并发
并行处理(Parallel Processing)是计算机系统中能同时执行两个或更多个处理的一种计算方法。并行处理可同时工作于同一程序的不同方面。并行处理的主要目的是节省大型和复杂问题的解决时间。
并发处理(concurrency Processing):指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机(CPU)上运行,但任一个时刻点上只有一个程序在处理机(CPU)上运行
并发的关键是你有处理多个任务的能力,不一定要同时。并行的关键是你有同时处理多个任务的能力。所以说,并行是并发的子集。
4、同步与异步
同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去;
异步是指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率。
举个例子,打电话时就是同步通信,发短息时就是异步通信。
threading module
1、 创建thread类
1 import threading,time 2 3 def f1(n): 4 print("f1......%s" %n) 5 time.sleep(int(n)) 6 7 def f2(n): 8 print("f2......%s" %n) 9 time.sleep(int(n)) 10 11 aa = threading.Thread(target=f1,args=("2",)) # 定义一个线程实例aa 12 aa.start() # 启动线程aa 13 14 bb = threading.Thread(target=f2,args=("5",)) # 生成一个线程实例bb 15 bb.start() # 启动线程bb 16 17 print("ending...")
2、thread类的实例方法
2.1 join()
在子线程完成运行之前,这个子线程的父线程将一直被阻塞。
2.2 setDaemon(block=False)
将线程声明为守护线程,必须在start() 方法调用之前设置,如果不设置为守护线程程序会被无限挂起。
当我们在程序运行中,执行一个主线程,如果主线程又创建一个子线程,主线程和子线程 就分兵两路,分别运行,那么当主线程完想退出时,会检验子线程是否完成。如果子线程未完成,则主线程会等待子线程完成后再退出。但是有时候我们需要的是只要主线完成了,不管子线程是否完成,都要和主线程一起退出,这时就可以 用setDaemon方法啦.
1 import threading,time 2 from time import sleep,ctime 3 4 def music(name): 5 print("{name} start listen music in the {time}".format(name=name,time=ctime())) 6 sleep(6) 7 print("Music is end...{time}...".format(time=ctime())) 8 9 def playgame(name): 10 print("{name} start playing game...{time}...".format(name=name,time=ctime())) 11 sleep(3) 12 print("Game is over...{time}...".format(time=ctime())) 13 14 threads = [] 15 godie = threading.Thread(target=music,args=("baby",)) 16 king = threading.Thread(target=playgame,args=("dachao",)) 17 threads.append(godie) 18 threads.append(king) 19 20 if __name__ == '__main__': 21 # godie.setDaemon(True) # 注意:必须在start之前,保护进程,True==》主进程无需等待子进程,全部关闭 22 king.setDaemon(True) 23 for i in threads: 24 # i.setDaemon(True) 25 i.start() 26 # i.join() # for循环也是主线程,godie和king依次执行完,主线程结束 27 28 godie.join() # godie和king按照for循环启动,godie阻塞主线程 29 # king.join() # king阻塞主线程,结束后主线程同步执行print语句 30 31 print("All end...{time}...".format(time=ctime()))
Thread实例对象的方法
# isAlive(): 返回线程是否活动的。 # getName(): 返回线程名。 # setName(): 设置线程名。
threading模块提供的一些方法: # threading.currentThread(): 返回当前的线程变量。 # threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。 # threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
其它:待整理
切换的操作者:操作系统
进程/线程切换原则:
1、时间片
2、遇到IO操作切换
3、优先级切换
IO密集型任务和计算密集型任务
IO密集型任务:程序存在大量IO操作
计算密集型任务:程序存在大量计算操作
对于PYTHON(无法利用多核):
多线程处理 IO密集型任务具有优势
计算密集型任务 不推荐使用多线程
Python中的线程是操作系统的原生线程,Python虚拟机使用一个全局解释器锁(Global Interpreter Lock)来互斥线程对Python虚拟机的使用。为了支持多线程机制,一个基本的要求就是需要实现不同线程对共享资源访问的互斥,所以引入了GIL。
GIL:在一个线程拥有了解释器的访问权之后,其他的所有线程都必须等待它释放解释器的访问权,即使这些线程的下一条指令并不会互相影响。
在调用任何Python C API之前,要先获得GIL
GIL缺点:多处理器退化为单处理器;优点:避免大量的加锁解锁操作
无论你启多少个线程,你有多少个cpu, Python在执行一个进程的时候会淡定的在同一时刻只允许一个线程运行。
所以,python是无法利用多核CPU实现多线程的。
这样,python对于计算密集型的任务开多线程的效率甚至不如串行(没有大量切换),但是,对于IO密集型的任务效率还是有显著提升的。