并发编程的一些方法和简单的原理

一,开启子进程的两种方式

总结:两种方式的特点和大概的区别

方式一,主要用函数的方式.主要在产生子进程的时候需要这样写

p=Process(target=task,args=('jack',这里是个元组如果一个元素也得加上逗号))    #如果需要传入字典的时候需要用kwargs = {}

from multiprocessing import Process
import time


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

#     在windows系统上,开启子进程的操作必须放到If__name__ == '__main__'的子代码中
if __name__ == '__main__':
    p = Process(target=task,args = ('jack'))
    p.start()  
# 只是向操作系统发送了一个开启子进程的信号,但是还没有来得及执行就进入主进程的下一步了
    time.sleep(1)  # 让主进程睡一段时间,子进程也会同时执行
    print('主进程')

方式二:主要定义了一个产生子进程的类,这种方式在产生子进程对象的时候写的比较简单

p=Myprocess('jack')

但是在类中需要定义一个传参的内置函数__init__和一个执行函数  def run(delf)

from multiprocessing import Process
import time


class Myprocess(Process):
    def __init__(self,name):
        super().__init__()
        self.name = name

    def run(self):
        print('%s is running' %self.name)
        time.sleep(3)
        print('%s is done' %self.name)

# 在windows系统上,开启子进程的操作必须放到'if __name__ == '__main__':的子代码中
if __name__ == '__main__':
    p=Myprocess('jack')
    p.start()# 只是向操作系统发送一个开启子进程的信号
    print('主进程')

二,join方法

总结:join方法主要是主进程等待子进程执行完毕后,再执行join方法后面的代码.

否则:主进程无法预知子进程什么时候才成运行完毕.用法如下:

# join:让主进程在原地等待,等待子进程运行完毕,不会影响子进程的执行
from multiprocessing import Process
import time

def task(name,n):
    print('%s is running' %name)
    time.sleep(n)
    print('%s is done' %name)

if __name__ == '__main__':
    # p1 = Process(target=task,args=('子1',1))
    # p2 = Process(target=task,args=('子2',2))
    # p3 = Process(target=task,args=('子3',3))
    #
    # start = time.time()
    # p1.start()
    # p2.start()
    # p3.start()
    # time.sleep(5)
    #
    # p1.join()
    # p2.join()
    # p3.join()
    #
    # print('主进程',(time.time()-start))

    # 上面写了很多重复代码,把重复代码写成两个循环
    start = time.time()
    p_1 = []
    for i in range(1,4):
        p = Process(target=task,args=('子%s'%i,i))
        p_1.append(p)
        p.start()

    for p in p_1:
        p.join()
    print('主进程',(time.time()-start))

三,进程之间内存空间的相互隔离

总结:主进程与子进程之间的内存空间中的变量是相互独立的,子进程可以调用和更改主进程内存空间的变量,但是更改后只在子进程中调用才会查看到更改的结果,并不会在主进程中查看到子进程更改的结果

from multiprocessing import Process

n = 100
def task():
    global n
    n = 0
    print('子进程中的n',n)

if __name__ == '__main__':
    p = Process(target = task)
    p.start()
    # p.join()
    print(n)

运行结果如下:

100
子进程中的n 0

四,进程对象其他相关属性或方法

4.1进程pid:每一个进程在操作系统内部都有一个独一无二的id,称之为pid

调用multiprocessing下面的current_process方法获取pid号
from multiprocessing import Process,current_process
import time

def task():
    print('%s is running' %current_process().pid)
    time.sleep(5)
    print('%s is done' %current_process().pid)

if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    print('主进程',current_process().pid)
调用os模块中的方法得到pid号,os.getppid()是获得产生该子进程的父进程的pid号
from multiprocessing import Process, current_process
import time
import os

def task():
    print('%s is running,它的父pid:%s' % (os.getpid(),os.getppid()))
    time.sleep(5)
    print('%s is done,它的父pid:%s' % (os.getpid(),os.getppid()))


if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    # 每一个主进程的父进程是产生该进程的软件
    print('主进程:%s,它的父pid:%s,' %(os.getpid(),os.getppid()))

4.2其他相关属性

from multiprocessing import Process, current_process
import time
import os

def task():
    print('%s is running,它的父pid:%s' % (os.getpid(),os.getppid()))
    time.sleep(5)
    print('%s is done,它的父pid:%s' % (os.getpid(),os.getppid()))

# 每一个进程都存在自己的名字,也可以后期更改名字
if __name__ == '__main__':
    p = Process(target=task,name='子进程')
    p.start()
    print(p.name)
    # 当主进程想要强制把子进程结束时,用terminate
    p.terminate()
    # 这是发出强制停止的信号,但是还没有执行,必须给它一个执行的时间
    time.sleep(1)
    # 判断子进程是否存活状态
    print(p.is_alive())
    print('主进程:%s,它的父pid:%s,' %(os.getpid(),os.getppid()))

五,僵尸进程与孤儿进程(只针对linux系统)

总结:当进程结束的时候,pid号还会保留(称之为僵尸进程),一直到父进程结束的时候回收它们,系统内部的pid号是有限的,不会一直产生.当父进程结束的时候,子进程还没有结束(称之为孤儿进程),子进程结束之后就由产生父进程的软件集体回收.

注:1,每一个子进程最后都会经历僵尸进程,而不一定会经历孤儿进程

2,当一个主进程进入一个死循环,主进程一直在产生子进程而没有结束的标志的时候可能对系统产生一点负累.而孤儿进程会定期回收,所以不会对系统产生负累

六,守护进程

总结:当一个子进程定义为守护进程的时候,不管它运行到哪里,只要主进程结束,它也会跟着结束.(有点像陪葬的赶脚)

定义一个子进程为守护进程:需要在start()之前加 daemon = True

#守护进程: 本质就是一个"子进程",该"子进程"的生命周期<=被守护进程的生命周期
from multiprocessing import Process
import time

def task(name):
    print('太监%s活着....' %name)
    time.sleep(3)
    print('太监%s正常死亡....' %name)

if __name__ == '__main__':
    p=Process(target=task,args=('jack',))
    p.daemon=True
    p.start()
    time.sleep(1)
    print('皇上:正在死...')

七,互斥锁

总结:同时产生很多子进程,而子进程里面的方法都是并发执行的.这时产生一些方法需要并发执行,一些方法需要串行执行的需求,就充分发挥了互斥锁的功能.互斥锁有两种使用方法:

互斥锁的一种执行的方法:
from multiprocessing import Process,Lock
import random,time,json


# 查看文档中的票的数量,也许查看的同时票已经被别人抢走了
def search(name):
    with open('db.json','rt',encoding='utf-8')as f:
        dic = json.load(f)

    time.sleep(1)
    print('%s 查看余票为 %s' %(name,dic['count']))


# 当查看到文档中的票数时,判断是否有票,如果有票,把文档中的票数减1,这样就完成了购票操作
def get(name):
    with open('db.json','rt',encoding='utf-8')as f:
        dic = json.load(f)

    if dic['count'] > 0:
        dic['count'] -= 1
        time.sleep(random.randint(1 , 3))
        with open('db.json','wt',encoding='utf-8')as f:
            json.dump(dic,f)
            print('%s 购票成功' % name)

    else:
        print('%s查看到没有票了' %name)


# 定义一个新的函数,把查看票数和购票放在一起
def task(name,mutex):
    search(name) # 并发执行
    mutex.acquire()
    get(name) # 需要串行执行的方法放到了这两个mutex之间
    mutex.release()



if __name__ == '__main__':
    mutex = Lock()
    for i in range(10):
        p = Process(target=task,args=('路人%s' %i,mutex))
        p.start()
#         p.join()   只能讲进程的额任务整体编程串行
互斥锁的另一种使用方法:
from multiprocessing import Process,Lock
import random,time,json


# 查看文档中的票的数量,也许查看的同时票已经被别人抢走了
def search(name):
    with open('db.json','rt',encoding='utf-8')as f:
        dic = json.load(f)

    time.sleep(1)
    print('%s 查看余票为 %s' %(name,dic['count']))


# 当查看到文档中的票数时,判断是否有票,如果有票,把文档中的票数减1,这样就完成了购票操作
def get(name):
    with open('db.json','rt',encoding='utf-8')as f:
        dic = json.load(f)

    if dic['count'] > 0:
        dic['count'] -= 1
        time.sleep(random.randint(1 , 3))
        with open('db.json','wt',encoding='utf-8')as f:
            json.dump(dic,f)
            print('%s 购票成功' % name)

    else:
        print('%s查看到没有票了' %name)


# 定义一个新的函数,把查看票数和购票放在一起
def task(name,mutex):
    search(name)# 并发执行

    with mutex:  (把需要串行的方法放到这个下面)
        get(name) 


if __name__ == '__main__':
    mutex = Lock()
    for i in range(10):
        p = Process(target=task,args=('路人%s' %i,mutex))
        p.start()
#         p.join()   只能讲进程的额任务整体编程串行

猜你喜欢

转载自blog.csdn.net/qq_42737056/article/details/82425575
今日推荐