进程
import multiprocessing
import os
def info(title):
print(title)
print(__name__)
print('father', os.getppid())
print('self', os.getpid())
print('--------')
if __name__ == "__main__": # 除了创建的子进程和子进程调用函数,其他的都是脚本主进程
# info('hello')
# 创建一个子进程调用函数
P = multiprocessing.Process(target=info,args=('hello python',))
P.start()
P.join() # 和多线程一样,也是等待的意思
print('hello word') # 若没有join则会独立运行
#结果
"""
hello python
__mp_main__
father 15416
self 15780
--------
hello word
"""
#如果把p.join()关闭了结果为
"""
hello word
hello python
__mp_main__
father 9080
self 16124
--------
"""
#自我理解一下:join()是阻塞下面的输出语句,等join()上面执行完,在执行下面的
join()
主进程阻塞等待子进程的退出, join方法要在close或terminate之后使用。
import multiprocessing
import os
import time
def info(title):
print(title)
time.sleep(2)
print(__name__)
print('father', os.getppid())
print('self', os.getpid())
print('--------')
if __name__ == "__main__":
p1 = multiprocessing.Process(target=info,args=('A1',))
p2 = multiprocessing.Process(target=info, args=('A2',))
p3 = multiprocessing.Process(target=info, args=('A3',))
p1.start()
p2.start()
p3.start()
p1.join()
p2.join()
p3.join()
# 这里的join只是为了卡住主进程,使得三个进程都执行完毕再执行print
# 这里很重要,以后多进程扫描文件需要完全等待几个进程全部执行完毕在汇总
print('all over')
'''
轮流执行
p1.start()
p1.join()
p2.start()
p2.join()
p3.start()
p3.join()
'''
#结果
"""
A1
A2
A3
__mp_main__
__mp_main__
__mp_main__
father 7208
self 3208
--------
father 7208
self 16300
--------
father 7208
self 2552
--------
all over
这里进程是同时执行的
"""
例题
# 4个进程需要计算5次,你可以想象4个进程并行4次计算任务后,还剩一次计算任务(任务4)没有完成,系统会等待4个进# 程完成后重新安排一个进程来计算。
from multiprocessing import Pool, cpu_count
import os
import time
def long_time_task(i):
print('子进程: {} - 任务{}'.format(os.getpid(), i))
time.sleep(2)
print("结果: {}".format(8 ** 20))
if __name__=='__main__':
print("CPU内核数:{}".format(cpu_count()))
print('当前母进程: {}'.format(os.getpid()))
start = time.time()
p = Pool(4)
for i in range(5):
p.apply_async(long_time_task, args=(i,))
print('等待所有子进程完成。')
p.close()
p.join()
end = time.time()
print("总共用时{}秒".format((end - start)))
"""
结果
CPU内核数:4
当前母进程: 15716
等待所有子进程完成。
子进程: 12912 - 任务0
子进程: 12828 - 任务1
子进程: 12008 - 任务2
子进程: 12376 - 任务3
结果: 1152921504606846976
子进程: 12912 - 任务4
结果: 1152921504606846976
结果: 1152921504606846976
结果: 1152921504606846976
结果: 1152921504606846976
总共用时4.950684309005737秒
"""
进程锁(lock)
# 进程同步
import os
import multiprocessing
import time
# 多进程,并发,可能乱序并发执行(主要看系统如何处理)
# 多进程加锁,挨个执行,也可能是乱序
def showdata(lock, i):
with lock:
print(multiprocessing.current_process().name)
time.sleep(2)
print(i)
if __name__ == "__main__":
lock = multiprocessing.RLock() # 创建锁
for num in range(10):
multiprocessing.Process(target=showdata, args=(lock, num)).start()
进程通信
# 进程通信
import multiprocessing
import os
def func(conn): # conn表示管道类型
print('func',os.getpid(), conn.recv()) # 收到的数据
conn.send(['a', 'b', 'c', 'd', 'e']) # 发送的数据
conn.close() # 关闭
if __name__ == "__main__":
conn_a, conn_b = multiprocessing.Pipe() # 创建一个管道,有两个口
# print(id(conn_a),id(conn_b))
# print(type(conn_a), type(conn_b)) #multiprocessing.connection.Connection链接,意思就是连接口
# 相当于在进程中conn_a.send(['a','b','c','d','e']),发送给conn_b
p = multiprocessing.Process(target=func, args=(conn_a,)).start()
conn_b.send([1, 2, 3, 4, 5, 6, 7]) # 发送数据给conn_a
print('mian',os.getpid(), conn_b.recv())
"""
func 14860 [1, 2, 3, 4, 5, 6, 7]
mian 14360 ['a', 'b', 'c', 'd', 'e']
"""
# 全局变量不可以进程共享
import multiprocessing
import os
data = []
def List():
global data
data.append(1)
data.append(2)
data.append(3)
print('p',os.getpid(),data)
if __name__ == '__main__':
p = multiprocessing.Process(target=List,args=()).start() # 子进程
data.append('a') # 脚本主进程
data.append('b')
data.append('c')
print('main',os.getpid(),data)
"""
全局变量不共享
1809 ['a', 'b', 'c']
1810 [1, 2, 3]
"""
队列的进程共享(queue)
队列的性质
1,获取不到,就一直等待(get())
2,往里放一个,取一个
Queue(maxsize=0)
maxsize参数 ,是给定空间的大小,不是元素长度的大小
Empty()
对空的 Queue 对象,调用非阻塞的get()(or get_nowait()) 时,引发的异常。
Full()
对满的 Queue 对象,调用非阻塞的 put() (or put_nowait()) 时,引发的异常。
Queue对象
Queue.put(item,lock=true,timeout=none)
timeout参数 :没有可获取的元素时,等待自定义几秒就会自己关闭。
Queue.put_nowait(item)
相当于 put(item, False) 。
Queue.get(item,lock=true,timeout=none)
timeout参数 :没有可获取的元素时,等待自定义几秒就会自己关闭。
Queue.get_nowait()
相当于 get(False) 。
注意 用timeout 就点用 try…except 捕获,要不然程序就会崩掉。
Queue.qsize( )
返回队列的大小,当获取不到时,就会报错。
Queue.empty()(常用)
如果队列为空,返回true,否则返回false 。
Queue.full()
如果队列是满的返回true,否则返回false。
Queue.task_done()
表示前面排队的任务已经被完成。被队列的消费者线程使用。每个 get() 被用于获取一个任务, 后续调用 task_done() 告诉队列,该任务的处理已经完成。
如果 join() 当前正在阻塞,在所有条目都被处理后,将解除阻塞(意味着每个 put() 进队列的条目的 task_done() 都被收到)。
大致理解是在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号
Queue.join()
阻塞至队列中所有的元素都被接收和处理完毕。
当条目添加到队列的时候,未完成任务的计数就会增加。每当消费者线程调用 task_done() 表示这个条目已经被回收,该条目所有工作已经完成,未完成计数就会减少。当未完成计数降到零的时候, join() 阻塞被解除
大致理解 : 实际上意味着等到队列为空,再执行别的操作
# 队列可以进程共享
import multiprocessing
import os
queue = multiprocessing.Queue()
# 注意队列只能单向,要么是父进程插入子进程取出,要么是子进程插入父进程取出
def func(myq):
print(os.getpid())
myq.put([1, 2, 3, 4]) # 子进程插入
if __name__ == '__main__':
print(os.getpid())
# queue.put(['a','b']) # 这里若是脚本父进程先插入了,子进程就没法再插入了
p = multiprocessing.Process(target=func, args=(queue,))
p.start()
print(queue.get()) # 脚本父进程取出
进程数据共享
import multiprocessing
def func(num):
num.value = 10
if __name__ == '__main__':
# multiprocessing.Value可以在不同进程之间共享数据
num = multiprocessing.Value('d', 1) # double float
print(num.value) # 单单num返回的结果 Synchronized wrapper for c_double(1.0)
p = multiprocessing.Process(target=func, args=(num,))
p.start()
p.join()
print(num.value)
进程数据共享
import multiprocessing
def func(num):
num.value = 10
if __name__ == '__main__':
# multiprocessing.Value可以在不同进程之间共享数据
num = multiprocessing.Value('d', 1) # double float
print(num.value) # 单单num返回的结果 Synchronized wrapper for c_double(1.0)
p = multiprocessing.Process(target=func, args=(num,))
p.start()
p.join()
print(num.value)
#结果 1.0
# 10.0
'''
Value(typecode_or_type, *args[, lock])
Value函数返回一个shared memory包装类,其中包含一个ctypes对象
typecode_or_type typecode列表如下
------------------------------------------------------------------
Type code C Type Python Type
'c' char character
'b' signed char int
'B' unsigned char int
'u' Py_UNICODE Unicode character
'h' signed short int
'H' unsigned short int
'i' signed int int
'I' unsigned int long
'l' signed long int
'L' unsigned long long
'f' float float
'd' double float
'''
进程字典列表共享
import multiprocessing
def func(mydict, mylist):
mydict["kongkong"] = "都太简单"
mydict["mykol"] = "啥都不会"
mylist.append(11)
mylist.append(22)
mylist.append(33)
if __name__ == "__main__":
# with multiprocessing.Manager() as MG:
# mydict=MG.dict()
# mylist=MG.list(range(5))
mydict = multiprocessing.Manager().dict()
# [0,1,2,3,4]
mylist = multiprocessing.Manager().list(range(5))
p = multiprocessing.Process(target=func, args=(mydict, mylist))
p.start()
p.join()
print(mylist)
print(mydict)
# print(list(range(5))) # 很牛逼的list
#结果
#[0, 1, 2, 3, 4, 11, 22, 33]
#{'kongkong': '都太简单', 'mykol': '啥都不会'}
进程列表数组共享
import multiprocessing
def func(num):
num[2] = 9999
if __name__ == '__main__':
# 不同进程之间实现数组共享
num = multiprocessing.Array('i', [1, 2, 3, 4, 5, 6]) # i代表int类型
print(num[:])
p = multiprocessing.Process(target=func, args=(num,))
p.start()
p.join()
print(num[:])
#结果
#[1, 2, 3, 4, 5, 6]
#[1, 2, 9999, 4, 5, 6]
课上练习
简单机器人对话
import multiprocessing
def M(conn):
while 1:
recv_ = conn.recv()
print('机器人收到:%s'%recv_)
if recv_ == '你好':
conn.send('你好吗')
elif recv_ == '学的怎么样':
conn.send('垃圾')
else:
conn.speed('哎,人生苦多,别写错了')
def P(conn):
y = 'y'
while y != 'n':
input_ = input('人说')
conn.send(input_)
print(conn.recv())
if __name__ == "__main__":
conn_M,conn_P = multiprocessing.Pipe() #创建
p_M = multiprocessing.Process(target=M,args=(conn_M,))
p_M.start()
# p_M.join()
P(conn_P)