多进程

1. 多进程

编写玩的程序在还没有运行的情况下,称之为程序。

正在运行的代码,就成了进程,进程除了包含代码外,还需要运行环境等。

在计算机上,我们应该如何实现多线程呢?

例1:我们来尝试实现唱歌和跳舞

在生活中我们唱一首歌和跳一支舞肯定是不间断的,这里我们用while循环代替

import time


def sing():
    while True:
        print("我正在唱歌……")
        time.sleep(1)


def dance():
    while True:
        print("我正在跳舞……")
        time.sleep(1)


if __name__ == '__main__':
    sing()
    dance()

但程序运行后发现一直在唱歌从未跳舞,这明显不符合我们的预期。这说明要同时唱歌跳舞需要一个新的方式来完成,这个新的方式就是多任务,其实操作系统中就可以同时运行多个任务。

多任务的实现分两种,一种是单核CPU实现多任务,另一种是多核CPU实现多任务

单核CPU:1.时间片轮换  2.优先度调度

多核CPU:1.并发 2.并行

下面我们用单核CPU来模拟多进程

2. 多进程的实现

在Python中要实现多线程需要用到os模块,os的模块就封装了常用的系统调用,下面我们用os模块中的fork来实现多进程。注意fork只能在Linux环境下才能运行成功。

下面是一个简单的多进程:

  2 import time
  3 
  4 
  5 def dance():
  6     while True:
  7         print("I am singing")
  8         yield 0
  9 
 10 
 11 def sing():
 12     while True:
 13         print("I am dancing")
 14         yield 0
 15 
 16 
 17 res =os.fork()
 18 if res == 0:
 19     print("Today is a good day , %s, %s" % (os.getpid(), os.getppid()))
 20 else:
 21     print("Today is a bad day , %s, %s" % (os.getpid(), res))

运行结果如下:getpid来获取当前进程的进程编号,os.getppid()方法案来获取当前进程的父进程编号。

Today is a bad day , 2894, 2895
Today is a good day , 2895, 2894

下面我们来实现同时唱歌和跳舞:

  1 import os
  2 
  3 
  4 def dance():
  5     while True:
  6         print("I am singing")
  7 
  8 
  9 def sing():
 10     while True:
 11         print("I am dancing")
 12 
 13 
 14 res =os.fork()
 15 if __name__=='__main__':
 16     if res == 0:
 17         dance()
 18     else:
 19         sing()

3. 多进程中的全局变量

下面我们来看看在多进程中共用一个全局变量会有何影响

  1 import os
  2 num = 0
  3 res = os.fork()
  4 
  5 
  6 def sum1():
  7     print("sum1 is runing")
  8     global num
  9     num +=10
 10     print(num)
 11     
 12 
 13 def sum2():
 14     print("sum2 is runing")
 15     global num
 16     num += 10
 17     print(num)
 18     
 19 
 20 if res == 0:
 21     print("The child process is running")
 22     sum1()
 23 else:
 24     print("The main process is running")
 25     sum2()
 26     

运行结果如下,发现共用一个全局变量的两个进程之间没有相互的影响。

The child process is running
The main process is running
sum2 is runing
10
sum1 is runing
10

4.多次调用fork函数

  1 import os
  2 
  3 res1 = os.fork()
  4 if res1 == 0:
  5     print("--------1---------")
  6 else:
  7     print("--------2---------")
  8 
  9 res2 = os.fork()
 10 if res2 == 0:
 11     print("--------3---------")
 12 else:
 13     print("--------4---------")
 14 
 15 print("-------5---------")

第一次运行结果如下:

--------1---------
--------2---------
--------4---------
-------5---------
--------4---------
-------5---------
--------3---------
-------5---------
--------3---------
-------5---------

第二次运行结果如下:

--------2---------
--------1---------
--------4---------
--------4---------
-------5---------
-------5---------
--------3---------
-------5---------
--------3---------
-------5---------

首先1、2之间1是子进程,2是主进程,主进程和子进程的执行顺序是没有规律的,这个不受程序员的控制,有操作系统的调度算法来控制。

5. window下的多进程

window下实现多进程要引入multiprocessing文件中的Process,需要注意的是在window环境下实现多进程,运行的主程序一定要放在main函数( if __name__=='__main__': )下。

5.1 函数实现方式(无参数)

import multiprocessing
import os


def dance():
    for i in range(10000):
        print("正在跳舞..........", os.getpid(), os.getppid())


def sing():
    for i in range(10000):
        print("正在唱歌...........", os.getpid(), os.getppid())


if __name__ == '__main__':
    print("程序开始运行")
    # 构造进程对象
    t1 = multiprocessing.Process(target=dance)
    t2 = multiprocessing.Process(target=sing)
    # 启动进程
    t1.start()
    t2.start()

    print("程序运行结束")

程序运行结果如下:

程序开始运行
程序运行结束
正在跳舞, 3288, 2940
正在跳舞, 3288, 2940
正在跳舞, 3288, 2940
正在跳舞, 3288, 2940
正在跳舞, 3288, 2940
正在跳舞, 3288, 2940
正在跳舞, 3288, 2940
正在唱歌,4492, 2940
正在跳舞, 3288, 2940
正在唱歌,4492, 2940
正在跳舞, 3288, 2940
……

在程序中,程序开始运行  程序运行结束 先运行 后运行进程,这是为什么呢? 

这是因为在window环境下单核CPU实现多进程时,开辟的进程都是子进程,而计算机创建一个进程是需要时间的,在这个短暂的时间里程序运行结束已经运行完了。

而在window环境下单核CPU实现多进程时,子进程和主进程是同时开辟的,谁先运行,是随机的,谁先创建完成谁先走一步。

5.2 函数实现方式(有参数)

from multiprocessing import Process


def run1(msg):
    while True:
        print("这个第二个子进程运行了,接收到参数:", msg)
        time.sleep(1)


def run2(msg, tp):
    while True:
        print("这个第二个子进程运行了,接收到参数:", msg, tp)
        time.sleep(1)


if __name__ == '__main__':
    print("主进程开始运行了......")
    t1 = Process(target=run1, args=("ran",))
    t2 = Process(target=run2, args=("sun", "ren"))
    t1.start()
    t2.start()

运行结果如下:

主进程开始运行了......
我正在唱歌……
这个第二个子进程运行了,接收到参数: ran
这个第二个子进程运行了,接收到参数: sun ren
……

6. 多进程中的一些方法和属性

6.1 一个方法 多个进程

def run(msg):
    for i in range(10000):
        print("The child processing is running")
        print(msg)
        print("The child processing is stop")


if __name__ == '__main__':
    print("The main processing is running")
    t1 = Process(target=run, args=("The child processing is doing something",), name="No1")
    t2 = Process(target=run, args=["Nothing"], name="No2")
    t1.start()
    t2.start()
    print(t1.name)
    print(t2.name)

在range传入的参数较小时,往往t1先运行完后t2才运行,担当range里传入的参数足够大时,会发现二者有交替出现的场景。

同样由于是window下单核CPU实现的多进程,t1.name和t2.name出现后子进程才会执行。

6.2 join方法

join方法会阻塞当前主进程运行,等待子进程运行完后再运行

def run(msg):
    for i in range(3):
        print("The child processing is running")
        print(msg)
        print("The child processing is stop")


if __name__ == '__main__':
    print("The main processing is running")
    t1 = Process(target=run, args=("The child processing is doing something",), name="No1")
    t2 = Process(target=run, args=["Nothing"], name="No2")
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print(t1.name)
    print(t2.name)

运行结果如下:

The main processing is running
The child processing is running
The child processing is doing something
The child processing is stop
The child processing is running
The child processing is doing something
The child processing is stop
The child processing is running
The child processing is doing something
The child processing is stop
The child processing is running
Nothing
The child processing is stop
The child processing is running
Nothing
The child processing is stop
The child processing is running
Nothing
The child processing is stop
No1
No2

6.3   终止进程

is_alive 判断进程是否存货,terminate阻断进程。

def run(msg):
    for i in range(3):
        print("The child processing is running")
        print(msg)
        print("The child processing is stop")


if __name__ == '__main__':
    print("The main processing is running")
    t1 = Process(target=run, args=("The child processing is doing something",), name="No1")
    t2 = Process(target=run, args=["Nothing"], name="No2")
    t1.start()
    t2.start()
    if t1.is_alive():
        t1.terminate()
    print(t1.name)
    print(t2.name)

运行结果如下:

The main processing is running
No1
No2
The child processing is running
Nothing
The child processing is stop
The child processing is running
Nothing
The child processing is stop
The child processing is running
Nothing
The child processing is stop

6.4  守护进程(daemo)

守护进程,依赖于主进程的守护进程 ,如果主进程结束, 那么子进程随之结束 ,常见于用一些不重要的、不想让用户看到的 比如版本更新等,

def run(msg):
    for i in range(3):
        print("The child processing is running")
        print(msg)
        print("The child processing is stop")


if __name__ == '__main__':
    print("The main processing is running")
    t1 = Process(target=run, args=("The child processing is doing something",), name="No1")
    t2 = Process(target=run, args=["Nothing"], name="No2")
    t1.daemon = True
    t1.start()
    t2.start()
    print(t1.name)
    print(t2.name)

7. 进程类的实现

from multiprocessing import Process
import time
"""
    进程的实现:
        1、需要基础multiprocessing模块中Process类
        2、重写run方法,run方法就是我们要执行进程代码
        
"""


class MyProcess(Process):

    def __init__(self,name, sex, age):
        super().__init__(name=name)
        self.sex = sex
        self.age = age

    # 在进程类中,run方法就是进程需要执行代码
    def run(self):
        print("一个独立的子进程运行了……", self.sex)
        time.sleep(5)
        print("子进程运行结束了……")


if __name__ == '__main__':
    print("主进程开始运行了……")
    m1 = MyProcess("Process-1", "男",16)
    m1.start()
    print(m1.name)
    print("主进程运行结束了……")

运行结果如下:

主进程开始运行了……
Process-1
主进程运行结束了……
一个独立的子进程运行了…… 男
子进程运行结束了……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值