首页 > 编程语言 > 详细

Python 之 进程 学习笔记

时间:2020-04-08 13:12:42      阅读:90      评论:0      收藏:0      [点我收藏+]

进程(Process)

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

  在当代面向线程设计的计算机结构中,进程是线程的容器。

  进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。

引入进程原因

  • 为了提高资源利用率和系统处理能力,现阶段计算机系统都是多道程序系统,即多道程序并发执行。
  • 优化系统资源,方便计算机调度,避免系统运算紊乱。
  • 进程是一种数据结构,能够清晰的刻画动态系统的内在规律,增加程序运行时的动态性。

进程特征

  • 动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。
  • 并发性:任何进程都可以同其他进程一起并发执行。
  • 独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位。
  • 异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进。

结构组成:程序、数据和进程控制块

  多个不同的进程可以包含相同的程序:一个程序在不同的数据集里就构成不同的进程,能得到不同的结果;但是执行过程中,程序不能发生改变。

进程与程序区别

  • 程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。
  • 而进程是程序在处理机上的一次执行过程,它是一个动态的概念。
  • 程序可以作为一种软件资料长期存在,而进程是有一定生命期的。
  • 程序是永久的,进程是暂时的。

并行

并行(Parallelism)

并行:指两个或两个以上事件(或线程)在同一时刻发生,是真正意义上的不同事件或线程在同一时刻,在不同CPU资源呢上(多核),同时执行。

特点

  • 同一时刻发生,同时执行。
  • 不存在像并发那样竞争,等待的概念。

并发

并发(Concurrency)

指一个物理CPU(也可以多个物理CPU) 在若干道程序(或线程)之间多路复用,并发性是对有限物理资源强制行使多用户共享以提高效率。

特点

  • 微观角度:所有的并发处理都有排队等候,唤醒,执行等这样的步骤,在微观上他们都是序列被处理的,如果是同一时刻到达的请求(或线程)也会根据优先级的不同,而先后进入队列排队等候执行。
  • 宏观角度:多个几乎同时到达的请求(或线程)在宏观上看就像是同时在被处理。

进程调度

  • 先来先服务调度法:按照先后顺序处理事件的一种算法。
  • 短作业调度法:又称为短进程优先算法,能有效减少平均周转时间。
  • 时间片轮转法:让每个进程在就绪队列中的等待时间与享受服务的时间成比例,也就是需要将CPU的处理时间分成固定大小的时间片,如果一个进程在被调度选中之后用完了系统规定的时间片,但又未完成要求的任务,则它自行释放自己所占有的CPU而排到就绪队列的末尾,等待下一次调度。同时,进程调度程序又去调度当前就绪队列中的第一个进程。
  • 多级反馈队列:多级反馈队列调度算法则不必事先知道各种进程所需的执行时间,而且还可以满足各种类型进程的需要,因而它是目前被公认的一种较好的进程调度算法。

 

进程状态介绍

技术分享图片

 

 

 

状态描述

  就绪(Ready)状态:当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行,这时的进程状态称为就绪状态。

  执行/运行(Running)状态:当进程已获得处理机,其程序正在处理机上执行,此时的进程状态称为执行状态。

  阻塞(Blocked)状态:正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。引起进程阻塞的事件可有多种,例如,等待I/O完成、申请缓冲区不能满足、等待信件(信号)等。

同步/异步
  同步(synchronous): 所谓同步就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列。

简言之,要么成功都成功,失败都失败,两个任务的状态可以保持一致。

  异步(asynchronous):所谓异步是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了。至于被依赖的任务最终是否真正完成,依赖它的任务无法确定,所以它是不可靠的任务序列。

Python 进程操作

multiprocess.Process模块

process模块是一个创建进程的模块,借助这个模块,就可以完成进程的创建。

语法:Process([group [, target [, name [, args [, kwargs]]]]])

由该类实例化得到的对象,表示一个子进程中的任务(尚未启动)。

注意:1. 必须使用关键字方式来指定参数;2. args指定的为传给target函数的位置参数,是一个元祖形式,必须有逗号。

参数介绍:

group:参数未使用,默认值为None。

target:表示调用对象,即子进程要执行的任务。

args:表示调用的位置参数元祖。

kwargs:表示调用对象的字典。如kwargs = {‘name‘:Jack, ‘age‘:18}。

name:子进程名称。

Python_process属性方法介绍

start() 启动进程,调用进程中的run()方法。
run() 进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法 。
terminate() 强制终止进程,不会进行任何清理操作。如果该进程终止前,创建了子进程,那么该子进程在其强制结束后变为僵尸进程;如果该进程还保存了一个锁那么也将不会被释放,进而导致死锁。使用时,要注意。
is_alive() 判断某进程是否存活,存活返回True,否则False。
join([timeout]) 主线程等待子线程终止。timeout为可选择超时时间;需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程 。
daemon 默认值为False,如果设置为True,代表该进程为后台守护进程;当该进程的父进程终止时,该进程也随之终止;并且设置为True后,该进程不能创建子进程,设置该属性必须在start()之前
name 进程名称。
pid 进程pid
exitcode 进程运行时为None,如果为-N,表示被信号N结束了。
authkey 进程身份验证,默认是由os.urandom()随机生成32字符的字符串。这个键的用途是设计涉及网络连接的底层进程间的通信提供安全性,这类连接只有在具有相同身份验证才能成功。

实例:

import os
from multiprocessing import Process
def Yux():
    print(os.getpid(), os.getppid(),88)     #20496 20404 88 ;子进程ID 与 父进程ID(此py文件进程ID)
    print("我是子进程")

if __name__=="__main__":
    print(os.getpid(),os.getppid())         #20404 18172 ;此py文件进程ID 与 pycharm-ID
    pi = Process(target=Yux)
    pi.start()      #在此程序里开启子进程

 

实例2(join 方法):

import time
from multiprocessing import Process
 
 
def func_one(name):
    print("My name is", name)
    time.sleep(2)
    print("This is func_one")
 
 
def func_two(name):
    print("My name is", name)
    time.sleep(2)
    print("This is func_two")
 
 
if __name__ == __main__:
    p_one = Process(target=func_one, args=("Jack",))
    p_two = Process(target=func_two, args=("Mick",))
    p_one.start()
    p_one.join()  # 主线程要等待func_one终止,才继续往下走
    p_two.start()

 

实例3(迭代处理进程的执行):

import time
from multiprocessing import Process
 
 
def func_one(name):
    print("My name is", name)
    time.sleep(1)
 
 
def func_two(age):
    print("My age is", age)
    time.sleep(5)
 
 
if __name__ == __main__:
    lst_one = []
    lst_two = []
    for i in range(5):
        p_one = Process(target=func_one, args=(Mike,))
        p_two = Process(target=func_two, args=(18,))
        p_one.start()
        p_two.start()
        lst_two.append(p_two)
        [p_two.join() for p_two in lst_two]  # 父进程要等子进程结束
    print("End")

 

实例4,以继承Process的方式开启进程

import os
from multiprocessing import Process
 
 
class MyProcess(Process):
    def __init__(self, name):
        super().__init__()
        self.name = name
 
    def run(self):
        print("进程为%s,父进程为%s" % (os.getpid(), os.getppid()))
        print("我的名字是%s" % self.name)
 
 
if __name__ == __main__:
    p_one = MyProcess(张三)
    p_two = MyProcess(李四)
    p_thr = MyProcess(王五)
 
    p_one.start()  # 自动调用run()
    p_two.start()
    p_thr.run()  # 直接调用run()
 
    p_one.join()
    p_two.join()
    # p_thr.join()  # 调用run()函数的不可以调用join()
 
    print("主进程结束")

注意:调用run()函数的不可以调用join()。

守护进程

守护进程就是会随着主进程的结束而结束的进程,具有以下两个特点:

  • 守护进程会在主进程代码执行结束后就终止。
  • 守护进程内无法再开启子进程,否则抛出异常。

实例一

import os
import time
from multiprocessing import Process
 
 
class MyProcess(Process):
    def __init__(self, name):
        super().__init__()
        self.name = name
 
    def run(self):
        print("进程为%s,父进程为%s" % (os.getpid(), os.getppid()))
        print("我的名字是%s" % self.name)
 
 
if __name__ == __main__:
    p_one = MyProcess(张三)
    p_two = MyProcess(李四)
    p_two.daemon = True  # 默认为False,必须在start()之前设置
    p_one.start()
    p_two.start()
    time.sleep(5)
    print("主进程结束")

实例二

from multiprocessing import Process
import time
 
 
def func_one():
    print("func_one")
    time.sleep(2)
    print("End func_one")
 
 
def func_two():
    print("func_two")
    time.sleep(3)
    print("End func_two")
 
 
if __name__ == __main__:
    p_one = Process(target=func_one)
    p_two = Process(target=func_two)
 
    p_one.daemon = True
    p_one.start()
    p_two.start()
    time.sleep(0.1)  # 时间太短,导致print("End func_one")无法打印
 
    print("主进程结束")

锁——Lock
 通过上面的研究,我们千方百计实现了程序的异步,让多个任务可以同时在几个进程中并发处理,他们之间的运行没有顺序,一旦开启也不受我们控制。尽管并发编程让我们能更加充分的利用IO资源,但是也给我们带来了新的问题。

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

使用加锁的形式实现了顺序的执行,但是程序又重新变成串行了,这样确实会浪费了时间,却保证了数据的安全。

from multiprocessing import Process, Lock
import time
import json
import random
 
 
def search():
    dic = json.load(open(db))
    time.sleep(random.random())  # 模拟读取数据
    print("\033[43m剩余票数:%s\033[0m" % dic[count])
 
 
def get():
    dic = json.load(open(db))
    time.sleep(random.random())  # 模拟网络延迟
    if dic[count] > 0:
        dic[count] -= 1  # 购票成功后减一
        time.sleep(1)
        json.dump(dic, open(db, w))
        print("\033[32m购票成功\033[0m")
    else:
        print("\033[31m尚无余票\033[0m")
 
 
def task(lock):
    lock.acquire()
    search()
    get()
    lock.release()
 
 
if __name__ == __main__:
    lock = Lock()
    for i in range(10):
        p = Process(target=task, args=(lock,))
        p.start()

加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改。加锁牺牲了速度,但是却保证了数据的安全。

事件
事件(Event),用于线程间通信,即程序中的其一个线程需要通过判断某个线程的状态来确定自己下一步的操作,就用到了event对象。

事件处理的机制:

全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,那么event.wait 方法时便不再阻塞。

clear:将“Flag”设置为False。

set:将“Flag”设置为True。

红绿灯实例:

from multiprocessing import Process, Event
import time
import random
 
 
def traffic_light(e):
    ‘‘‘信号灯函数‘‘‘
    while 1:  # 红绿灯得一直亮着,要么是红灯要么是绿灯
        if e.is_set():  # True,代表绿灯亮,那么此时代表可以过车
            time.sleep(5)  # 所以在这让灯等5秒钟,这段时间让车过
            print(\033[31m红灯亮!\n车辆等待中...\033[0m)  # 绿灯亮了5秒后应该提示到红灯亮
            e.clear()  # 把is_set设置为False
        else:
            time.sleep(5)  # 此时代表红灯亮了,此时应该红灯亮5秒,在此等5秒
            print(\033[32m绿灯亮!\n车辆通过中...\033[0m)  # 红的亮够5秒后,该绿灯亮了
            e.set()  # 将is_set设置为True
 
 
def car_status(num, e):
    e.wait()  # 车等在红绿灯,此时要看是红灯还是绿灯,如果is_set为True就是绿灯,此时可以过车
    print(第%s辆车过去了 % num)
 
 
if __name__ == __main__:
    event = Event()
    tra_light = Process(target=traffic_light, args=(event,))  # 信号灯的进程
    tra_light.start()
    for i in range(50):  # 描述50辆车的进程
        if i % 3 == 0:
            time.sleep(random.randint(1, 5))  # 车辆出现时间随机
        car = Process(target=car_status, args=(i + 1, event,))
        car.start()

队列(Queue)

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

Queue[maxsize]:maxsize是队列中允许的最大项数。如果省略此参数,则无大小限制。底层队列使用管道和锁定实现。另外,还需要运行支持线程以便队列中的数据传输到底层管道中。

队列实例,生产者消费者模型:

from multiprocessing import Process,Queue
import time,random

def xiao(q,name):
    while True:
        q.get()
        time.sleep(random.randint(2,5))
        print("%s 消费了产品" % name)

def sheng(q,name):
    for i in range(10):
        time.sleep(random.random())
        q.put("dog")
        print("%s 生产了产品" % name)

if __name__ == __main__:
    q = Queue()
    p = Process(target=xiao,args=(q,"光芒"))
    p.start()
    p1 = Process(target=sheng,args=(q,"生产者"))
    p1.start()

 

 

 

————————————————
版权声明:本文为CSDN博主「Akaxian」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_33567641/article/details/81947832

 

Python 之 进程 学习笔记

原文:https://www.cnblogs.com/yx3445/p/12658724.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!