python之进程

1,什么是进程呢?python

进程(Process)是计算机中的关于某数据集合上的一次运算,是系统进行资源分配和调度的基本单位,是操做系统结构的基础。进程是程序的实体。linux

动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。 并发性:任何进程均可以同其余进程一块儿并发执行 独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位; 异步性:因为进程间的相互制约,使进程具备执行的间断性,即进程按各自独立的、不可预知的速度向前推动 结构特征:进程由程序、数据和进程控制块三部分组成。 多个不一样的进程能够包含相同的程序:一个程序在不一样的数据集里就构成不一样的进程,能获得不一样的结果;可是执行过程当中,程序不能发生改变。
进程的特征
程序是指令和数据的有序集合,其自己没有任何运行的含义,是一个静态的概念。 而进程是程序在处理机上的一次执行过程,它是一个动态的概念。 程序能够做为一种软件资料长期存在,而进程是有必定生命期的。 程序是永久的,进程是暂时的。
程序与进程的区别

同一个程序执行两次,就会在操做系统中出现两个进程,能够同时运行一个软件,分别作不一样的事情也不会混乱。算法

2,进程调度json

要想多个进程交替运行,操做系统必须对这些进程进行调度,须要进程调度算法。安全

(1)先来先服务调度算法服务器

(2)短做业优先调度算法网络

(3)时间片轮转发session

(4)多级反馈队列:设置多个就绪队列,为各个队列赋予不一样优先级。优先级逐个下降,当一个程序在时间片仍未执行完,便加入到下一对列,直到执行完。每当有新进程进来,优先执行。并发

3,进程的并行与并发app

并行:并行是指二者同时执行,例:比赛,两我的都在不停的往前跑(资源够用。好比三个线程,四核的cpu)

并发:并发是指在资源有限的状况下,二者交替轮流使用资源。(单核cpu)A走一段hou

,让B走一段,B用完后在给A,交替使用。

区别:

并行:是从微观上,就是在一个精确的时间片刻,有不一样的程序在执行,要求必须有多个处理器。

并发:是从宏观上,在一个时间段能够看出同时执行的,好比一个服务器同时处理多个session

4,同步异步阻塞非阻塞

操做系统调度算法控制时,程序会进入几个状态:就绪,运行,阻塞。

(1)同步与异步

同步:完成一个任务须要依赖另外一个任务,只等别依赖的任务完成后,才能执行本身的。

异步:不须要等待依赖任务完后成,只需通知被依赖的任务执行。

(2)阻塞非阻塞

阻塞:程序中止不在执行

5,进程的建立与结束

multiprocess模块

(1)

Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化获得的对象,表示一个子进程中的任务(还没有启动) 强调: 1. 须要使用关键字的方式来指定参数 2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号 参数介绍: 1 group参数未使用,值始终为None 2 target表示调用对象,即子进程要执行的任务 3 args表示调用对象的位置参数元组,args=(1,2,'egon',) 4 kwargs表示调用对象的字典,kwargs={'name':'egon','age':18} 5 name为子进程的名称
View Code
1 p.start():启动进程,并调用该子进程中的p.run() 2 p.run():进程启动时运行的方法,正是它去调用target指定的函数,咱们自定义类的类中必定要实现该方法 3 p.terminate():强制终止进程p,不会进行任何清理操做,若是p建立了子进程,该子进程就成了僵尸进程,使用该方法须要特别当心这种状况。若是p还保存了一个锁那么也将不会被释放,进而致使死锁 4 p.is_alive():若是p仍然运行,返回True 5 p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,须要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程
方法
1 p.daemon:默认值为False,若是设为True,表明p为后台运行的守护进程,当p的父进程终止时,p也随之终止,而且设定为True后,p不能建立本身的新进程,必须在p.start()以前设置 2 p.name:进程的名称 3 p.pid:进程的pid 4 p.exitcode:进程在运行时为None、若是为–N,表示被信号N结束(了解便可) 5 p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络链接的底层进程间通讯提供安全性,这类链接只有在具备相同的身份验证键时才能成功(了解便可)
属性
在Windows操做系统中因为没有fork(linux操做系统中建立进程的机制),在建立子进程的时候会自动 import 启动它的这个文件,而在 import 的时候又执行了整个文件。所以若是将process()直接写在文件中就会无限递归建立子进程报错。因此必须把建立子进程的部分使用if __name__ ==‘__main__’ 判断保护起来,import 的时候  ,就不会递归运行了。
注意事项
# from multiprocessing import Process # import os # def func(i): # print('%d:子进程%d干的事,父进程:%d'%(i,os.getpid(),os.getppid())) # # if __name__=='__main__': # p_lst=[] # for i in range(10): # p=Process(target=func,args=(i,)) # p.start() # p_lst.append(p) # # p.join() #等子进程执行完,才执行下面的 # for p in p_lst:p.join() # print('---主进程---')

多进程同时运行,子进程的执行顺序不是根据启动顺序决定的。

(2)经过继承Process类开启进程。

import os from multiprocessing import Process class MyProcess(Process): def __init__(self,name): super().__init__() self.name=name def run(self):                                 #必须有run方法
        print(os.getpid()) print('%s 正在和女主播聊天' %self.name) p1=MyProcess('wupeiqi') p2=MyProcess('yuanhao') p3=MyProcess('nezha') p1.start() #start会自动调用run
p2.start() # p2.run()
p3.start() p1.join() p2.join() p3.join() print('主线程')

注:进程之间的数据不是共享的(数据的隔离问题)

from multiprocessing import Process def work(): global n n=0 print('子进程内: ',n) if __name__ == '__main__': n = 100 p=Process(target=work) p.start() print('主进程内: ',n)

5,守护进程

子进程会随主进程的结束而结束。

主进程建立守护进程

       其一:守护进程会在主进程代码执行结束后终止

       其二:守护进程内没法再开子进程,不然抛异常。

 

# start 开启一个进程 # join 用join可让主进程等待子进程结束

# 守护进程 # 守护进程会随着主进程的代码执行结束而结束 # 正常的子进程没有执行完的时候主进程要一直等着
import time from multiprocessing import Process def func(): print('--'*10) time.sleep(15) print('--'*10) def cal_time(): while True: time.sleep(1) print('过去了1秒') if __name__ == '__main__': p = Process(target=cal_time) p.daemon = True     # 必定在开启进程以前设置
 p.start() p2 = Process(target=func)  # 15s
 p2.start() for i in range(100):    # 10s
        time.sleep(0.1) print('*'*i) p2.join() # 守护进程的进程的做用:
    # 会随着主进程的代码执行结束而结束,不会等待其余子进程 # 守护进程 要在start以前设置 # 守护进程中 不能再开启子进程
View Code

6,锁

  当多个进程使用同一份数据资源的时候,就会引起数据安全或顺序混乱问题

from multiprocessing import Lock

import time import json import random from multiprocessing import Lock from multiprocessing import Process def search(i): with open('ticket') as f: print(i,json.load(f)['count']) def get(i): with open('ticket') as f : ticket_num=json.load(f)['count'] time.sleep(random.random()) if ticket_num>0: with open('ticket','w') as f: json.dump({'count':ticket_num-1},f) print('%s买到票了'%i) else: print('%s没买到票'%i) def task(i,lock): search(i) lock.acquire() #锁,钥匙
 get(i) lock.release() #还钥匙

if __name__=='__main__': lock=Lock() for i in range(20): p=Process(target=task,args=(i,lock)) p.start()
抢票的例子
#加锁能够保证多个进程修改同一块数据时,同一时间只能有一个任务能够进行修改,即串行的修改,没错,速度是慢了,但牺牲了速度却保证了数据安全。
虽然能够用文件共享数据实现进程间通讯,但问题是: 1.效率低(共享数据基于文件,而文件是硬盘上的数据) 2.须要本身加锁处理 #所以咱们最好找寻一种解决方案可以兼顾:一、效率高(多个进程共享一块内存的数据)二、帮咱们处理好锁问题。这就是mutiprocessing模块为咱们提供的基于消息的IPC通讯机制:队列和管道。
队列和管道都是将数据存放于内存中 队列又是基于(管道+锁)实现的,可让咱们从复杂的锁问题中解脱出来, 咱们应该尽可能避免使用共享数据,尽量使用消息传递和队列,避免处理复杂的同步和锁问题,并且在进程数目增多时,每每能够得到更好的可获展性。

7,信号量(from multiprocessing import Semaphore)

信号量基于内部的计数器,能够有多个锁钥匙。

import random import time from multiprocessing import Process from multiprocessing import Semaphore def sing(i,sem): sem.acquire() print('%s :进去 ktv '%i) time.sleep(random.randint(2,8)) print('%s : 离开 ktv'%i) sem.release() if __name__=='__main__': sem=Semaphore(5)          #钥匙数,参数能够设置
    for i in range(20): Process(target=sing,args=(i,sem)).start()
例子

8,事件(from multiprocessing import Event)

python线程的事件用于主线程控制其余线程的执行,事件主要提供了三个方法 set、wait、clear。 事件处理的机制:全局定义了一个“Flag”,若是“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,若是“Flag”值为True,那么event.wait 方法时便再也不阻塞。 clear:将“Flag”设置为False set:将“Flag”设置为True
介绍
# import time # import random # from multiprocessing import Process # from multiprocessing import Event # # def traffic_light(e): # while True: # if e.is_set(): # e.is_set()是否阻塞 True就是绿灯 False就是红灯 # time.sleep(3) # print('红灯亮') # e.clear()  # else: # time.sleep(3) # print('绿灯亮') # e.set() # def car(i,e): # e.wait() # print('%s车经过'%i) # # if __name__=='__main__': # e=Event() # tra=Process(target=traffic_light,args=(e,)) # tra.start() # for i in range(100): # if i%6 == 0: # time.sleep(random.randint(1,3)) # car_pro=Process(target=car,args=(i,e)) # car_pro.start()
例子

9,队列(from multiprocessing import Queue)

建立共享的进程队列,Queue是多进程安全的队列,可使用Queue实现多进程之间的数据传递。

Queue([maxsize]) 建立共享的进程队列。maxsize是队列中容许的最大项数。若是省略此参数,则无大小限制。底层队列使用管道和锁定实现。另外,还须要运行支持线程以便队列中的数据传输到底层管道中。 Queue的实例q具备如下方法: q.get( [ block [ ,timeout ] ] ) 返回q中的一个项目。若是q为空,此方法将阻塞,直到队列中有项目可用为止。block用于控制阻塞行为,默认为True. 若是设置为False,将引起Queue.Empty异常(定义在Queue模块中)。timeout是可选超时时间,用在阻塞模式中。若是在制定的时间间隔内没有项目变为可用,将引起Queue.Empty异常。 q.get_nowait( ) 同q.get(False)方法。 q.put(item [, block [,timeout ] ] ) 将item放入队列。若是队列已满,此方法将阻塞至有空间可用为止。block控制阻塞行为,默认为True。若是设置为False,将引起Queue.Empty异常(定义在Queue库模块中)。timeout指定在阻塞模式中等待可用空间的时间长短。超时后将引起Queue.Full异常。 q.qsize() 返回队列中目前项目的正确数量。此函数的结果并不可靠,由于在返回结果和在稍后程序中使用结果之间,队列中可能添加或删除了项目。在某些系统上,此方法可能引起NotImplementedError异常。 q.empty() 若是调用此方法时 q为空,返回True。若是其余进程或线程正在往队列中添加项目,结果是不可靠的。也就是说,在返回和使用结果之间,队列中可能已经加入新的项目。 q.full() 若是q已满,返回为True. 因为线程的存在,结果也多是不可靠的(参考q.empty()方法)。
方法介绍
#1.进程之间通讯 可使用multiprocessing 的 Queue模块 #2.队列有两种建立方式 第一种不传参数 这个队列就没有长度限制 ;传参数,建立一个有最大长度限制的队列 #3.提供两个重要方法;put get #4.qsize

from multiprocessing import Process from multiprocessing import Queue # def q_put(q): # q.put('hello') # # def q_get(q): # print(q.get()) # # if __name__ =='__main__': # q = Queue() # p = Process(target=q_put,args=(q,)) # p.start() # p1 = Process(target=q_get, args=(q,)) # p1.start()
View Code

生产者消费者模型

# 经过队列实现了 主进程与子进程的通讯 子进程与子进程之间的通讯 # 生产者消费者模型

# 我要生产一个数据 而后 给一个函数 让这个函数依赖这个数据进行运算 拿到结果 —— 同步过程

# 作包子 和 吃包子
import time def producer(q):  # 生产者
    for i in  range(100): q.put('包子%s'%i) def consumer(q): # 消费者
    for i in range(100): time.sleep(1) print(q.get()) if __name__ == '__main__': q = Queue(10)   # 托盘
    p = Process(target=producer,args=(q,)) p.start() c1 = Process(target=consumer, args=(q,)) c2 = Process(target=consumer, args=(q,)) c1.start() c2.start() # 首先 对于内存空间来讲 每次只有不多的数据会在内存中 # 对于生产与消费之间的不平衡来讲
    # 增长消费者或者增长生产者来调节效率
View Code
相关文章
相关标签/搜索