学无止境

少年辛苦终身事,莫向光阴惰寸功。——唐·杜荀鹤《题弟侄书堂》


Liunx编程-python进程

什么是多任务


  • 程序中的多任务

  • 如果有多件事情是同时进行,我们把这种情况叫做多任务。Linux 是真正的多任务、多用户操作系统,windows是多任务操作系统,但不是真正意义上的多用户操作系统。

  • 并发和并行


  • 时间片轮转

  • 时间片轮转调度是一种最古老,最简单,最公平且使用最广的算法,又称RR调度。每个进程被分配一个时间段,称作它的时间片,即该进程允许运行的时间优先数调度算法常用于批处理系统中。在进程调度中,每次调度时,系统把处理机分配给就绪队列中优先数最高的进程。它又分为两种:==非抢占式优先数算法和抢占式优先数算法。==
  • ==非抢占式优先权算法==:系统一旦把处理机分配给就绪队列中优先权最高的进程后,该进程便一直执行下去,直至完成
  • ==抢占式优先权调度算法==:系统同样把处理机分配给优先权最高的进程,使之执行.但在其执行期间,只要又出现了另一个其优先权更高的进程,进程调度程序就立即停止当前进程(原优先权最高的进程)的执行,重新将处理机分配给新到的优先权最高的进程
  • ==系统的进程会比开发者开发的优先调度==
  • 并发和并行

  • 并发:在多核系统里的,同时执行多个进程,一般会情况下会有些进程没有机会执行,这种情况是并发。
  • Concurrent(并发)
  • Parallel(并行)
  • 多任务在程序中的实现–进程和线程

  • 多任务系统中有3个功能单位:任务、进程和线程

  • os.fork函数创建进程


  • 程序和进程区别

  • 程序:编写完毕的代码,在没有运行的时候,称之为程序(代码)

  • 进程:正在运行着的代码,就成为进程,进程占用了内存和cpu等资源。

  • 进程,除了包含代码以外,还有需要运行的环境等,所以和程序(代码)是有区别的.

  • fork( )

  • 注意,fork函数,只在Unix/Linux/Mac上运⾏,windows不可以

  • fork函数的使用

  • PID(进程控制符)

  • PID是各进程的身份标识,程序一运行系统就会自动分配给

  • 返回三个值0,大于0的值,-1

  • #如果返回0,当前是子进程

  • #如果返回大于0,当前是父进程

  • fork函数原理

  • fork下的函数体父子各一份

  • 普通的函数调⽤,调⽤⼀次,返回⼀次,但是fork()调⽤⼀次,返回两次,因 为操作系统⾃动把当前进程(称为⽗进程)复制了⼀份(称为⼦进程),然 后,分别在⽗进程和⼦进程内返回。 ⼦进程永远返回0,⽽⽗进程返回⼦进程的ID。

  • 这样做的理由是,⼀个⽗进程可以fork出很多⼦进程,所以,⽗进程要记下 每个⼦进程的ID,⽽⼦进程只需要调⽤getppid()就可以拿到⽗进程的ID。


getpid()、getppid()


-get pid()当前进程的Pid os.getppid()当前父进程的pid

  • 子进程永远返回0,而父进程返回子进程的ID,这样做的理由是,一个父进程可以fork出很多子进程,所以,父进程要记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程的ID,getpid()得到当前进程的ID。

小结



进程与进程之间数据不共享


  • 进程间数据不同享
  • fork时子进程获得父进程代码和数据段、共享库、堆和栈的复制,所以变量的地址也是一样的
  • 多进程中,每个进程中所有数据(包括全局变量)都各有拥有一份,互不影响。 fork时子进程获得父进程代码和数据段、共享库、堆和栈的拷贝,所以变量的地址也是一样的,并且在某一个进程中修改相同变量的值,在另外一个进程中的相同变量的值不会修改。

  • 多次fork问题

  • 父子和子进程的执行顺序

  • 父进程、子进程执行顺序没有规律,完全取决于操作系统的调度算法
  • 注意在pycharm上要使用sleep休眠一会,等待子进程执行在推出,次退出主进程,否则子进程没有机会执行
  • 扩展-for炸弹


创建跨平台的进程–==multiprocessing==


  • Windows无法使用fork调用创建进程,那在windows中怎么创建进程呢?由于Python是跨平台的,自然也应该提供一个跨平台的多进程支持,multiprocessing模块就是跨平台版本的多进程模块,使用改模块的Process类可以创建进程

  • 使用Process创建进程

  • 如果时全局变量子进程与主进程互不干扰

  • join等待子进程结束

  • 创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例对象,用start()方法启动,这样创建进程比fork()还要简单。

  • join 让你的主进程让步

  •   p.join()
    
  • join()没加参数是指子进程执行完毕之后,主进程才可以加入 join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步。

  • 子进程只要是完成了“目标”,就自杀

  • 如果进程没有完成任务,可用他杀调用p.terminate()

  • Process语法结构

  • Process([group [, target [, name [, args [, kwargs]]]]])

  • target:表示这个进程实例所调用对象;

  • args:表示调用对象的位置参数元组;

  • kwargs:表示调用对象的关键字参数字典;

  • name:为当前进程实例的别名;

  • group:大多数情况下用不到;

  • p.terminate()不管任务是否完成,立即终止

  • is_alive()判断进程是否存活

  • join([timeout]):是否等待进程实例执行结束,或等待多少秒;

  • start():启动进程实例(创建子进程);

  • run():如果没有给定target参数,对这个对象调用-

  • start()方法时,就将执行对象中的run()方法;

  • terminate():不管任务是否完成,立即终止;

  • Process类常用属性:

  • name:当前进程实例别名,默认为Process-N,N为从1开始递增的整数;

  • pid:当前进程实例的PID值;


进程的创建–自定义Process子类


  • 自定义Process子类

  • 只要启动start自动调用类里的run方法
  • run不能手动调用
  • ==只要时创建进程子类,必须重写run方法==
  • 如果自己定义了__ init__就必须调用父类的super().__ init__()

  • 进程池(Pool)


  • ultiprocessing模块提供的Pool方法。
  • 阻塞式:添加一个执行一个,执行完毕,才并且返回,然后接着添加下一个
  • 非阻塞式:全部添加到队列,立刻返回,并没有等他执行完毕,当执行完毕后有回掉,回掉种发携带结果
  • from multiprocessing import Pool
    
  • apply_async非阻塞式

  • apply_async(func[, args[, kwds]])
  • 用非阻塞方式调用func(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程),args为传递给func的参数列表,kwds为传递给func的关键字参数列表;
  • pool.apply_async(func,args=(tuple),callback=)
  • 如果你的回掉函数有参数,是通过当前任务的返回值
  • callback=回掉函数
  • pool.close()#不再添加其他的进程
  • 进程池:最大是Tool(n)n
  • n个只要有一个结束了,进程池立马会将释放的进程分配,依此类推
  • 只要一个进程结束,扔出一个回掉函数,父进程立刻调用callback得到一个返回值
  • apply堵塞式

  • 阻塞式没有回掉函数
  • apply(func[, args[, kwds]]):使用阻塞方式调用func
  • multiprocessing.Pool常用函数解析

  • apply_async(func[, args[, kwds]]) :使用非阻塞方式调用func(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程),args为传递给func的参数列表,kwds为传递给func的关键字参数列表;
  • apply(func[, args[, kwds]]):使用阻塞方式调用func
  • close():关闭Pool,使其不再接受新的任务;
  • terminate():不管任务是否完成,立即终止,针对的是非阻塞式。
  • join():主进程阻塞,等待子进程的退出, 必须在close或terminate之后使用;
  • 阻塞和非阻塞的区别

  • 应用进程请求i/o操作(recv)时,如果数据未准备好请求是否立即返回
  • 不立即返回:阻塞式
  • 立即返回:非阻塞式
  • 阻塞式:任务一起交给pool则pool立刻打印全部
  • 非阻塞式:排队进入每次只能执行一个

  • 使用Queue实现进程间通信


  • Python中主要使用Queue(队列)、Manage支持管道通信、套接字( socket )等等实现进程间通信。

  • Queue的使用

  • Python中在multiprocessing模块的Queue类可以实现进程之间的数据传递,Queue本身是一个消息列队程序

  • from multtiprocessing import Quese

  • Queue.empty()在不同平台有差异

  • Queue的参数说明

  • 初始化Queue()对象时(例如:q=Queue()),若括号中没有指定最大可接收的消息数量,或数量为负值,那么就代表可接受的消息数量没有上限(直到内存的耗尽);

  • Queue.qsize():返回当前队列包含的消息数量

  • Queue.empty():如果队列为空,返回True,反之False

  • Queue.full():如果队列满了,返回True,反之False;

  • .Queue.get([block[, timeout]]):获取队列中的一条消息,然后将其从列队中移除,block默认值为True;如果block使用默认值,且没有设置timeout(单位秒),消息列队如果为空,此时程序将被阻塞(停在读取状态),直到从消息列队读到消息为止,如果设置了timeout,则会等待timeout秒,若还没读取到任何消息,则抛出"Queue.Empty"异常; 2)如果block值为False,消息列队如果为空,则会立刻抛出"Queue.Empty"异常

  • Queue.get_nowait():相当Queue.get(False);

  • .Queue.put(item,[block[, timeout]]):将item消息写入队列,block默认值为True;(阻塞式)如果block使用默认值,且没有设置timeout(单位秒),消息列队如果已经没有空间可写入,此时程序将被阻塞(停在写入状态),直到从消息列队腾出空间为止,如果设置了timeout,则会等待timeout秒,若还没空间,则抛出"Queue.Full"异常; 2)如果block值为False,消息列队如果没有空间可写入,则会立刻抛出"Queue.Full"异常;

  • Queue.put_nowait(item):相当Queue.put(item, False);

  • 进程池中的使用Manager()中的Queue

  • from multiprocessing import Manager

  • 没有长度限制

  • 如果使用的式进程池,则队列 queue=Menage().Queue()

  • 不能使用queue.Queue()

  • 打印进度

  • \r 换行,光标再上一行

  • %’%%‘输出一个单一的%