20170530——进程_多进程_共享数据

本文介绍了Python中的多进程管理,包括进程阻塞、进程创建、多进程的理解、以及multiprocessing包的使用。强调了在Unix/Linux/Mac上运行的fork函数和Windows的区别。详细讲解了如何获取进程ID,区分线程和进程,以及使用subprocess创建子进程。还探讨了进程间的通讯方式如管道Pipe,进程池Pool,以及不同方式的共享数据,如Queue、Array和Value。
摘要由CSDN通过智能技术生成

进程

进程阻塞:
multiprocessing.lock()
定义一个进程(把阻塞当做实参args):
#args=(,)必须是一个元组,num是for循环创建的第几个进程
multiprocessing.Process(target=showdatax,args=(lock,num)).start         
多进程:
threading和multiprocessing的一些理解
  • multiprocessing包是Python中的多进程管理包。
  • 与threading.Thread类似,它可以利用multiprocessing.Process对象来创建一个进程。
  • 该进程可以运行在Python程序内部编写的函数。
  • 该Process对象与Thread对象的用法相同,也有start(), run(), join()的方法。
  • 此外multiprocessing包中也有Lock/Event/Semaphore/Condition类 (这些对象可以像多线程那样,通过参数传递给各个进程),用以同步进程,其用法与threading包中的同名类一致。
  • 所以,multiprocessing的很大一部份与threading使用同一套API,只不过换到了多进程的情境。

注意,fork函数,只在Unix/Linux/Mac上运行,windows不可以
import os
pid = os.fork()     #fork之后会记录父进程的值,子进程为0
if pid == 0:
    print('哈哈1')
else:
    print('哈哈2')
##运行结果
哈哈2
哈哈1

10_获取进程编号id:

获取当前进程的pid的方法为:getpid()

获取父进程的pid的方法为:getppid()

#coding=utf-8
import os
import time
# 注意,fork函数,只在Unix/Linux/Mac上运行,windows不可以
pid = os.fork()
if pid == 0:
    print('哈哈1---pid = %d---ppid = %d----'%(os.getpid(), os.getppid()))
else:
    print('哈哈2---pid = %d---'%os.getpid())
time.sleep(1)
11_区分线程和进程————获取名字、id
线程可以获取当前名字:threading.current_thread().name

进程可以获取当前名字:
p1 = multiprocessing.Process(target=showname,args=("go1",))
print(p1.name)      #Process-1
        也可以获取pid:
        print(p1.pid)   #7708
小结__常用过去进程pid值得方法是去进程执行的目标函数内os.getpid 或os.getppid
def  showname(name):
    time.sleep(2)
    print("hello",name,os.getpid(),os.getppid())

20_subprocess标准子进程
import  subprocess

pingP=subprocess.Popen(args="ping www.qq.com",shell=True)#shell进程
pingP.wait()#主进程等待子进程结束
print(pingP.pid)#进程ID
print(pingP.returncode)#返回值  成功结果返回0(至少表现出来是这样的)
##运行结果
正在 Ping www.qq.com [182.254.18.159] 具有 32 字节的数据:
来自 182.254.18.159 的回复: 字节=32 时间=20ms TTL=52
来自 182.254.18.159 的回复: 字节=32 时间=10ms TTL=52
来自 182.254.18.159 的回复: 字节=32 时间=11ms TTL=52
来自 182.254.18.159 的回复: 字节=32 时间=16ms TTL=52

182.254.18.159Ping 统计信息:
    数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
    最短 = 10ms,最长 = 20ms,平均 = 14ms
11924
0
21_subprocess标准子进程+管道Pipe
import  subprocess
import  time
pingP=subprocess.Popen(args=["ping","www.qq.com"],
                       shell=True,
                       stdout=subprocess.PIPE)#shell进程
print(pingP.poll())     #进程状态
pingP.wait()    #强制要求主进程等待子进程结束
time.sleep(0.0000001)
# pingP.kill()  #杀死进程
print(pingP.stdout.read().decode("GBK"))#read是UTF-8,转化为GBK
print(pingP.pid)    #进程ID
print(pingP.returncode)     #返回值
##运行结果
None            #子进程处于运行状态,未执行完,所以子进程返回None

正在 Ping www.qq.com [182.254.18.159] 具有 32 字节的数据:
来自 182.254.18.159 的回复: 字节=32 时间=9ms TTL=52
来自 182.254.18.159 的回复: 字节=32 时间=20ms TTL=52
来自 182.254.18.159 的回复: 字节=32 时间=7ms TTL=52
来自 182.254.18.159 的回复: 字节=32 时间=6ms TTL=52

182.254.18.159 的 Ping 统计信息:
    数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
    最短 = 6ms,最长 = 20ms,平均 = 10ms

4912
0       #强制要求主进程等待子进程完成才结束程序,子进程执行完,所以返回0
小结____subprocess

我们可以使用subprocess包来创建子进程,但这个包有两个很大的局限性:
1) 我们总是让subprocess运行外部的程序,而不是运行一个Python脚本内部编写的函数。
2) 进程间只通过管道进行文本交流。
以上限制了我们将subprocess包应用到更广泛的多进程任务。

这样的比较实际是不公平的,因为subprocessing本身就是设计成为一个shell,而不是一个多进程管理包。


30_多进程
#-*- coding=utf-8 -*-
from multiprocessing import Process
import os
# 子进程要执行的代码
def run_proc(name):
    print('子进程运行中,name= %s ,pid=%d...' % (name, os.getpid()))
if __name__=='__main__':
    print('父进程 %d.' % os.getpid())
    p = Process(target=run_proc, args=('test',))
    print('子进程将要执行')
    p.start()
    p.join()
    print('子进程已结束')
##运行结果
父进程 7488.
子进程将要执行
子进程运行中,name= test ,pid=10844...
子进程已结束
40_进程通讯——管道Pipe
import multiprocessing

def  func(conn): #conn管道数据类型
    conn.send([1,2,3,4,5])#发送数据
    print(conn.recv())
    conn.close()#关闭

if __name__=="__main__":
    #如果duple=False,管道为单向,conn_A只能接受,conn_B只能发送
    conn_A,conn_B=multiprocessing.Pipe(duplex=True)     #开启管道    duplex默认为True,双向管道
    print(type(conn_A),type(conn_B))
    print(id(conn_A),id(conn_B))
    #开启管道
    p=multiprocessing.Process(target=func,args=(conn_B,))
    p.start()
    conn_A.send(["a","b","c"])
    print(conn_A.recv())#收数据
    p.join()
50_进程池Pool
import  multiprocessing
import time

def  go(i):
    time.sleep(3)
    print("第%d次"%i)
    return  i+100

def  show(arg):
    print("what---->",arg)

if __name__=="__main__":
    pool=multiprocessing.Pool(5)#创建一个进程池有5个进程
    print("start")
    for  i  in range(10):
        pool.apply_async(func=go,args=(i,),callback=show)   #进程并发(5个一起执行),并发返回值,不阻塞主进程(主进程直接print("end")),callback获取返回的值,当做show的实参
        #print(pool.apply(func=go, args=(i,)))  #进程同步,阻塞主进程(等待所有子进程执行完,才print("end")),无法get值,处理结果
        # print(pool.apply_async(func=go, args=(i,)).get())    #进程同步(一个一个执行),可以get出值,作另外的插座
        #go,函数,args参数,callback处理结果
    print("end")
    pool.close()#封闭进程池,不再添加
    pool.join()#等待

#apply_async异步,处理结果,start end->执行
#apply,不可以处理结果,start,end 之间执行
#print(pool.apply_async(func=go, args=(i,)).get()) 获取进程返回结果start,end 之间执行
##执行结果          #不阻塞主进程,直接print(”end“)
start
end0次
what----> 1001次
what----> 1012次
what----> 1023次
what----> 1034次
what----> 1045次
what----> 1056次
what----> 1067次
what----> 1078次
what----> 1089次
what----> 109
60_每个进程独享各自的list资源
import  multiprocessing
import time
import os
#进程安全,可以收集,每个进程拷贝一份,不安全(list,set,tuple,dict)
datalist=[]#每个进程都有单独全局变量,每个进程拷贝一份,互相独立

def adddata(i):
    datalist.append(i)
    print("hello",i)
    print(os.getpid(),datalist)#打印每个进程list


if __name__=="__main__":
    for i  in range(10):
        p=multiprocessing.Process(target=adddata,args=(i,))
        p.start()

    time.sleep(10)
    print("datalist",datalist)
    for i  in datalist:
        print(i)
#有0到9,10个进程,每一个数字代表一个进程
hello 0
612 [0]
hello 2
5484 [2]
hello 1
9468 [1]
hello 3
11412 [3]
hello 4
11852 [4]
hello 6
6376 [6]
hello 7
4276 [7]
hello 5
12516 [5]
hello 8
6960 [8]
hello 9
11620 [9]
datalist []
61_共享数据(各自进程独立)——进程multiprocessing.Queue+list
import  multiprocessing
import time
import os
#进程安全,可以收集,每个进程拷贝一份,不安全(list,set,tuple,dict)
datalist=[]#每个进程都有单独全局变量,每个进程拷贝一份,互相独立
queue=multiprocessing.Queue()

def adddata(queue,i):
    datalist.append(i)
    queue.put(datalist)#每个进程压入数据
    # queue.put(["023"])#每个进程压入数据
    print("hello",i)
    print(os.getpid(),datalist)#打印每个进程list


if __name__=="__main__":
    lastlist = []  #汇总结果
    for i  in range(10):
        p=multiprocessing.Process(target=adddata,args=(queue,i,))#创建进程
        # p.join()
        p.start()#开启      #没有join,进程并发执行,乱序
        #p.join()        #进程是同步执行,乱序
        listlite=queue.get()#get一次,取出一次数据
        print("get",listlite,os.getpid())
        lastlist+=listlite #结果汇总

    print(lastlist)#打印结果
hello 0
13228 [0]
get [0] 8940
hello 1
11544 [1]
get [1] 8940
hello 2
12620 [2]
get [2] 8940
hello 3
2400 [3]
get [3] 8940
hello 4
get [4] 8940
10320 [4]
hello 5
11448 [5]
get [5] 8940
hello 6
12872 [6]
get [6] 8940
hello 7
8232 [7]
get [7] 8940
hello 8
8364 [8]
get [8] 8940
hello 9
2712 [9]
get [9] 8940
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
62_共享数据(各自进程独立)——进程multiprocessing.Array
import multiprocessing

temp=multiprocessing.Array("i",[1,2,3,4])#进程不安全数组不作为参数,安全,当作参数

def add(i):
    temp[i]=100+i
    print(id(temp))
    for item in temp:
        print(i,"---->",item)

if  __name__=="__main__":
    for i in range(2):
        p=multiprocessing.Process(target=add,args=(i,))
        p.start()       #进程并发,乱序强资源,0和1进程,都有可能先打印
#运行结果
46016720
0 ----> 100
0 ----> 2
0 ----> 3
0 ----> 4
46147792
1 ----> 1
1 ----> 101
1 ----> 3
1 ----> 4
63_共享数据(各自进程独立)——进程multiprocessing.Value/Array
import  multiprocessing

#Array Value共享数据,必须当作参数,
def  f(n,a):
    n.value=9999
    a[0]=8888


if __name__=="__main__":
    arr=multiprocessing.Array("i",[1,2,3,4,5]) #数据共享,当作参数
    num=multiprocessing.Value("d",0.0) #d是一个类型,%d,%s,

    p=multiprocessing.Process(target=f,args=(num,arr))
    p.start()
    p.join()

    print(arr[:])
    print(num.value)
[8888, 2, 3, 4, 5]
9999.0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值