多进程

# e多进程

进程的实质就是就是正在执行的程序

底层的cpu级别中根本就不会出现多个程序一起执行的情况,多核cpu能够同时执行对应核数的程序,cpu使用的是时间片段的方式进行程序执行,由于切换的非常快,看起来就像是同时执行多个程序

为了看清实际的动作,使用的fork()进行编程,fork()只能在linux中执行,windows执行会直接报错

代码:

```python

import os

def test1():

    for i in range(3):

        print('进程1')

def test2():

    for i in range(5):

        print('进程2')

pid = os.fork() # 返回当前进程的子进程id,由于这里是分裂进程,子进程实际上在执行这一句的时候是没有pid值的,因此系统给的值是0

pids = os.fork()

if pid == 0: # 表示子进程,pid的值实际上是当前进程的子进程id,如果当前就是子进程则id=0

    test1()

else:

    test2()

print('执行结束')

```

程序在执行到os.fork()的时候进行自动的分裂,主进程分裂一个子进程,这里存在两个fork()

在第一个pid=os.fork()的时候存在一个主进程一个子进程,在主进程和子进程执行pids=os.fork()的时候主进程再次分裂一个子进程,二原来的子进程执行继续分裂为两个子进程.所以此时整个程序存在四个进程

进程id的查询

```python

os.getpid() # 查询当前的进程的进程id

os.getppid() # 查询当前进程的父进程id

```

当一个进程进行分裂的时候,主进程还是原来的进程,分裂的子进程的父进程id能够在子进程查到,但是子进程没有继续分裂则子进程的子进程id为0

# 进程的内存复制性质

当进程进行分裂的一瞬间,主进程实际上存在自己的内存中间中会有很多变量,而子进程是新建立的,实际上子进程会在分裂的时候复制主进程中的内存去开辟一个新内存,那么这两个内存实际上相互独立,因此在分裂之前定义的变量实际上是双份,子进程中的各自对变量进行操作,其结果将互不影响

```python

import os

# 关于全局变量的操作

num = 0

pid = os.fork()

# 创建多进程

if pid == 0:

    num += 1

    print(f'{num}')

else:

    num += 2

    print(f'{num}')

# 因为多进程的状态下实际上在执行进程分裂的时候子进程就会复制父进程的内存空间

输出结果1,2

```

# 能够跨平台使用的多进程模块

使用的是multiprocessing中的Process

这是一个类,想使用这个类先实例化一个对象,类上面存在多个方法,当实例化对象的时候类本身是没有立即执行进程分裂,而在执行start方法的时候才分裂,实例化对象的时候只是进行对象参数的传入和初始化

代码入下

```python

import time

from multiprocessing import Process  # 导入多进程模块

import os

def test1(args):

    time.sleep(1)

    print(f'{os.getpid()}子进程1进程号,传入的参数{type(args)}')

    print(f'父进程id{os.getppid()}')

def test2(args1,args2):

    time.sleep(2)

    print(f"{os.getpid()}子进程2进程号,传入的参数{args1,args2}")

    print(f'父进程id{os.getppid()}')

def main():

    # 创建进程对象

    p1 = Process(target=test1,args=(1,)) # 第一个进程

    p1.start() # 启动进程

    p2 = Process(target=test2,args=(10,12)) # 第二个进程

    p2.start()

    # 主进程执行

    print(f'主进程main{os.getpid()}')

if __name__ == '__main__':

    main()

```

其中参数的传入有点坑,本身Process上面有args和kwargs两个参数,前一个是传一般的参数,后一个传的是关键字参数,一般的位置参数通常是一个可迭代的对象,在实例化的时候要么是元组要么是列表,而kwargs是关键字参数,直接传入的是字典

target表示分裂的进程需要执行对应的函数的函数名

在函数的接收的时候,如果传入的args不止一个元素,那么函数就要接收对应个数的元素,不用去计较参数名,但是一旦是kwargs参数则表明是关键字参数,参数名必须一致

```python

from multiprocessing import Process

def test(x,y,key1,key2):

    print(f'args参数{x}和{y},kwags参数为:{key1,key2}')

def main():

    p1 = Process(target=test,args=[1,2],kwargs={'key1':10,'key2':20})

    # 启动p1分裂进程

    p1.start()

    print('结束')

if __name__ == '__main__':

    main()

```

执行结果:

```python

结束

args参数1和2,kwags参数为:(10, 20)

```

# 使用类的多进程写法

```shell

import os

import time

from multiprocessing import Process

# 进行类的写法

class MyProcess(Process):

    def __init__(self,args,**kwargs):

        # 可以有两种方式进行父类的初始化

        super(MyProcess, self).__init__()

        # 或者使用的是

        # Process.__init__()

        self.args = args

        self.kwargs = kwargs

    def run(self): # 这里必须写run,固定格式,在对象start的时候就自动执行这里的run

        time.sleep(2)

        print(f'在类里面进行进程执行{os.getpid()},参数为{self.args},关键字参数为:{self.kwargs}')

if __name__ == '__main__':

    # 实例化一个对象

    my_dict = {'key1':0,'key2':1}

    p1 = MyProcess(111,**my_dict)

    p1.start()

    # p1.join()

    print('主进程结束')

```

类的进程写法中需要注意的是类方法的问题,必须写run,这种是固定的写法,在继承父类的情况写写init的时候需要将父类的初始化方法执行,否则会报错

# 进程池

进程池说白了就是自行设定的容器,如果有三个容器,需要执行的进程有10个,则每个容器只能执行一个进程,多余7个在外面排队等着,三个正在执行的进程谁先结束,则会空一个容器出来,那么其余的7个进程只能有一个进到容器中进行执行,就像排队一样,这就是进程池的作用,你可以自己规定容器的个数

```python

from multiprocessing import Pool # 导入进程池

import os

import random

import time

def show(i):

    print(f'这里是进程:{os.getpid()},循环次数{i}')

    # 随机睡眠时间

    time.sleep(random.random()*2)

if __name__ == '__main__':

    pool = Pool(3) # 创建三个容器

    # 进行循环开启进程

    for i in range(10):

        pool.apply_async(show,(i,)) # 开启异步执行

    # 开启进程池之后进行关闭进程池

    pool.close()

    # 执行等待所有的进程执行完成

    pool.join()

    # 最后执行主线程

    print('主线程结束')

```

# 多进程之间的通信

进程与进程之间实际上是两个独立的内存空间,那么变量之间是没哟办法进行传递的,如果需要进行传递,则需要进行公共的内存来保存两个进程之间的变量信息,这个公共保存变量的内存空间实际上是利用队列的存储方式进行存储,先进的先出存储方式.因此如果需要进行变量的传递,进程不能直接传到另一个进程中,而是先将需要的数据传递到中间的公共内存部分,也就是队列里面,另外一个进程则从公共的部分里面进行获取数据,从而实现进程之间的通信

采用的是Queue的方式进行传递,Queue就像一个公共存储的地方,两个进程可以从中进程数据的拿取

```python

import time

from multiprocessing import Process,Queue

# 进程之间的通信使用的是队列的方式

def put_function(q):

    data = ['string','list','dict',{'key':'int'}]

    for i in data:

        q.put(i)

    print('将data存进中间的队列')

def get_function(q):

    time.sleep(2) # 保证put里面有数据,该进程先执行则将直接结束,所以进行延迟

    while True:

        data = q.get()

        if data: # 判定队列中是否有值,如果有则输出

            print(data)

        else:

            break

if __name__ == '__main__':

    # 创建队列

    q = Queue() # 通常并不限制队列中的数据个数

    p1 = Process(target=put_function, args=(q,))

    p2 = Process(target=get_function, args=(q,))

    # 以上是创建了两个进程但是还没有执行

    # 执行p1进程

    p1.start()

    p2.start()

```

这里比较难受的是当如果不进行设置时间延迟,则可能导致p2进程先向队列中进行数据拿取,而此时p1还没有将数据put进队列,从而直接到时p2进程进入break结束掉,这里进行延迟就是为了保证p2在拿数据的时候存在数据,当然为了更安全起见还可以在p2.start()之前进行p1.join()操作,在p1没有结束之前不执行后面的代码

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,133评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,682评论 3 390
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,784评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,508评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,603评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,607评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,604评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,359评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,805评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,121评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,280评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,959评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,588评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,206评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,442评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,193评论 2 367
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,144评论 2 352

推荐阅读更多精彩内容