多进程理论部分:
1.什么是进程
进程:正在进行的一个过程或者说一个任务,而负责执行任务的则是cpu。单核+多道,实现进程的并发执行

2.进程与程序的区别
程序仅仅只是一堆代码而已,而进程指的是程序的运行过程

3.并发与并行
无论是并行还是并发,在用户看来都是‘同时’运行的,不管是进程还是线程,都只是一个任务而已,真正干活的是CPU,CPU来做这些任务,而一个cpu同一时刻只能执行一个任务。
1.并发:是伪并发,即看起来是同时运行,单个cpu+多道技术就可以实现并发,(并行也属于并发)

你是一个cpu,你同时谈了三个女朋友,每一个都可以是一个恋爱任务,你被这三个任务共享
要玩出并发恋爱的效果,
应该是你先跟女友1去看电影,看了一会说:不好,我要拉肚子,然后跑去跟第二个女友吃饭,吃了一会说:那啥,我
去趟洗手间,然后跑去跟女友3开了个房

2.并行:同时运行,只是具备多个cpu才能实现并行

单核下,可以利用多道技术,多个核,每个核也都可以利用多道技术(多道技术是针对单核而言的

         有四个核,六个任务,这样同一时间有四个任务被执行,假设分别被分配给了cpu1,cpu2,cpu3,cpu4,

         一旦任务1遇到I/O就被迫中断执行,此时任务5就拿到cpu1的时间片去执行,这就是单核下的多道技术

         而一旦任务1的I/O结束了,操作系统会重新调用它(需知进程的调度、分配给哪个cpu运行,由操作系统说了算),可能被分配给四个cpu中的任意一个去执行

所有现代计算机经常会在同一时间做很多件事,一个用户的PC(无论是单cpu还是多cpu),都可以同时运行多个任务(一个任务可以理解为一个进程)。

    启动一个进程来杀毒(360软件)

    启动一个进程来看电影(暴风影音)

    启动一个进程来聊天(腾讯QQ)

所有的这些进程都需被管理,于是一个支持多进程的多道程序系统是至关重要的

多道技术概念回顾:内存中同时存入多道(多个)程序,cpu从一个进程快速切换到另外一个,使每个进程各自运行几十或几百毫秒,这样,虽然在某一个瞬间,一个cpu只能执行一个任务,但在1秒内,cpu却可以运行多个进程,这就给人产生了并行的错觉,即伪并发,以此来区分多处理器操作系统的真正硬件并行(多个cpu共享同一个物理内存)

4.进程的创建
但凡是硬件,都需要有操作系统去管理,只要有操作系统,就有进程的概念,就需要有创建进程的方式,一些操作系统只为一个应用程序设计,比如微波炉中的控制器,一旦启动微波炉,所有的进程都已经存在。
1.一个进程在运行过程中开启了子进程(如nginx开启多进程,os.fork,subprocess.Popen等)

5.进程的终止

       1. 正常退出(自愿,如用户点击交互式页面的叉号,或程序执行完毕调用发起系统调用正常退出,在linux中用exit,在windows中用ExitProcess)

  2. 出错退出(自愿,python a.py中a.py不存在)

  3. 严重错误(非自愿,执行非法指令,如引用不存在的内存,1/0等,可以捕捉异常,try...except...)

  4. 被其他进程杀死(非自愿,如kill -9)

 

6.进程的层次结构

无论UNIX还是windows,进程只有一个父进程,不同的是:

  1. 在UNIX中所有的进程,都是以init进程为根,组成树形结构。父子进程共同组成一个进程组,这样,当从键盘发出一个信号时,该信号被送给当前与键盘相关的进程组中的所有成员。

  2. 在windows中,没有进程层次的概念,所有的进程都是地位相同的,唯一类似于进程层次的暗示,是在创建进程时,父进程得到一个特别的令牌(称为句柄),该句柄可以用来控制子进程,但是父进程有权把该句柄传给其他子进程,这样就没有层次了。

7.进程的状态

tail -f access.log |grep '404'

  执行程序tail,开启一个子进程,执行程序grep,开启另外一个子进程,两个进程之间基于管道'|'通讯,将tail的结果作为grep的输入。

  进程grep在等待输入(即I/O)时的状态称为阻塞,此时grep命令都无法运行

  其实在两种情况下会导致一个进程在逻辑上不能运行,

  1. 进程挂起是自身原因,遇到I/O阻塞,便要让出CPU让其他进程去执行,这样保证CPU一直在工作

  2. 与进程无关,是操作系统层面,可能会因为一个进程占用时间过多,或者优先级等原因,而调用其他的进程去使用CPU。

  因而一个进程由三种状态

 

多进程操作:
1.开启子进程的两种方式

方式一:
from multiprocessing import Process
import time

def task(name):
    print('%s is runing'%name)
    time.sleep(3)
    print('%s id done' %name)

if __name__=='__main__':
    # 在windows系统之上,开启子进程的操作一定要放到这下面
    # Process(target=task,kwargs={'name':'egon'})
    p=Process(target=task,args=('egon',))
    p.start() # 向操作系统发送请求,操作系统会申请内存空间,然后把父进程的数据拷贝给子进程,作为子进程的初始状态
    print('======主')

编码结果:
======主
egon is running
egon is done
方式二:
from multiprocessing import Process
import time

class MyProcess(Process):
    def __init__(self,name):
         super(MyProcess,self).__init__()
         self.name=name
    def run(self):
       print('%s is runing'%self.name)
       time.self(3)
       print('%s is done' %self.name)

if __name__=='__main__':
   p=MyProcess('egon')
   p.start()
   print('')

代码结果:
  主
  egon is running
  egon is done

2.进程的内存空间相互隔离

from multiprocessing import Process
import time

x=1000

def task():
    time.sleep(3)
    global x
    x=0
    print('12323',x)

if __name__=='__main__':
   print(x)
   p=Process(target=task)
   p.start()
   time.sleep(5)
   print(x)

代码结果:
1000
12323  0
1000

3.父进程等待子进程结束

from multiprocessing import Process
import time
x=1000

def task():
    time.sleep(3)
    global x
    x=0
    print('12323',x)

if __name__ == '__main__':
    p=Process(target=task)
    p.start()

    p.join() # 让父亲在原地等
    print(x)

代码结果:
12323  0
1000

4.进程对象的其他属性:

进程对象的其他方法一:terminate 和 is_alive
from multiprocessing import Process
import time
import random

def task(name):
    print('%s is piaoing'%name)
    time.sleep(random.randrange(1,5))
    print('%s is piao end' %name)

if __name__=='__main__':
    p1=Process(target=task,args=('egon',))
    p1.start()

    p1.terminate()  #关闭进程,不会立即关闭,所以用is_alive立刻查看的结果可能还是存活的
    print(p1.is_alive())  #结果为True

    print('')
    print(p1.is_alive())   #结果为False



进程对象的其他属性:name与pid
from multiprocessing import Process
import time
import random

def task(name):
    print('%s is piaoing'%name)
    time.sleep(random.randrange(1,5))
    print('%s is piao end' %name)

if __name__=='__main__':
    p1=Process(target=task,args=('egon',),name='子进程')  #可以用关键字参数来指定进程名
    p1.start()

    print(p1.name,p1.pid)

代码结果:
子进程 6904
egon is piaoing
egon is piao end

 

posted on 2018-04-24 16:49  muzinianhua  阅读(103)  评论(0编辑  收藏  举报