目录
使用subprocess创建进程
打开其他的exe也是创建进程的一种形式,不是吗
比如要打开cmd,然后输入命令ping www.baidu.com
# !/usr/bin/env python
# encoding: utf-8
import subprocess
ret = subprocess.Popen(['ping.exe', 'www.baidu.com'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True)
out = ret.stdout.read()
gbk_data = out.decode('gbk')
print(gbk_data)
或者是使用ipconfig查看本机ip地址
# !/usr/bin/env python
# encoding: utf-8
import subprocess
ret = subprocess.Popen(['ipconfig.exe'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True)
out = ret.stdout.read()
gbk_data = out.decode('gbk')
print(gbk_data)
更多使用方式请参考:
https://www.cnblogs.com/sunailong/p/5162748.html
使用multiprocessing
Multiprocessing中的Process描述一个进程的对象,接受两个参数,一个是传入一个目标函数target,和参数的元组args;
p.start()启动对应的线程,但只要当主进程使用.join后(或者使用sleep)子线程才有机会去运行
使用multiprocessing创建单个进程
# !/usr/bin/env python
# encoding: utf-8
import multiprocessing as mp
import os
def do_soming(what):
print("process id:{0}, do what:{1}".format(os.getpid(), what))#获取当前进程的id
if __name__ == '__main__':
p = mp.Process(target=do_soming, args=('zengraoli',))#创建进程
p.start()#启动进程
p.join()#等待进程结束
使用multiprocessing创建多个进程
# !/usr/bin/env python
# encoding: utf-8
import multiprocessing as mp
import os
import time
def do_soming(*what):
print("process id:{0}, number:{1}, do what:{2}".format(os.getpid(), what[0], what[1]))#获取当前进程的id
time.sleep(5)#等待5秒后退出
if __name__ == '__main__':
for i in range(4):
p = mp.Process(target=do_soming, args=(str(i), 'zengraoli',))# 创建进程
print("item_process.start")
p.start()#启动进程
p.join()#阻塞等待进程
print("main close")
使用terminate()终止进程
当发现某个进程等待时间过长了或者控制不住了,可以使用terminate()来终止
# !/usr/bin/env python
# encoding: utf-8
import multiprocessing as mp
import os
import time
def do_soming(*what):
while True:
print("控制不住自己了..process id:{0}, number:{1}, do what:{2}".format(os.getpid(), what[0], what[1])) # 获取当前进程的id
if __name__ == '__main__':
process_list = []#存放所以进程对象的list
for i in range(4):
p = mp.Process(target=do_soming, args=(str(i), 'zengraoli',))#创建进程
print("item_process.start")
process_list.append(p)
p.start()#启动进程
time.sleep(10)
#等待所有进程
for item_process in process_list:
item_process.terminate()#杀掉那些二货
print("main close")
进程池Pool
我们其实能创建的进程数是有限的,毕竟cpu的能力也就这么多了,加上创建进程是一个比较耗时的操作,如果利用了Pool,预先分配一些进程,当有任务过来的时候,假如有空闲线程,那么任务立即执行,否则进行等待,这大大提高了效率
比如下面的程序,预先分配了4个线程,但我需要执行的任务是20个,那么可以用Pool这么做
# !/usr/bin/env python
# encoding: utf-8
import multiprocessing as mp
import os
import time
def do_soming(*what):
print("控制不住自己了..process id:{0}, number:{1}, do what:{2}".format(os.getpid(), what[0], what[1])) # 获取当前进程的id
time.sleep(5)
print("process id:{0} end".format(os.getpid()))
if __name__ == '__main__':
p = mp.Pool(processes=4)
for i in range(10):
p.apply_async(do_soming, args=(str(i), "zeng"))
print("waiting...")
p.close()
p.join()
print("main close")
你可以看到每次是4个进程启动、结束的
apply_async是每次都会同时调用所以的进程池的进程一起执行
Pool中一次性开启的N个进程,貌似在内部按顺序执行的,不知道会不会是个坑
apply会保证池子中只同时运行一个进程,是不是看起来一般情况下用这个函数的不多呢
# !/usr/bin/env python
# encoding: utf-8
import multiprocessing as mp
import os
import time
def do_soming(*what):
print("控制不住自己了..process id:{0}, number:{1}, do what:{2}".format(os.getpid(), what[0], what[1])) # 获取当前进程的id
time.sleep(5)
print("process id:{0} end".format(os.getpid()))
if __name__ == '__main__':
p = mp.Pool(processes=4)
for i in range(10):
p.apply(do_soming, args=(str(i), "zeng"))
print("waiting...")
p.close()
p.join()
print("main close")
假如进程只需要做某种运算,Pool给我们提供了map操作,只需要传入对应的数据即可,例如要对数据进行求平方的操作
# !/usr/bin/env python
# encoding: utf-8
import multiprocessing as mp
def do_soming(x):
print("do_soming begin.")
return list(map(lambda i:i**2, x))
if __name__ == '__main__':
x = [list(range(5)), list(range(5, 10)),
list(range(10, 15)), list(range(15, 20))]
with mp.Pool(4) as p:
print(p.map(do_soming, x))
print("main end.")
apply_async还能接受返回值,但是获取返回值是阻塞的
# !/usr/bin/env python
# encoding: utf-8
import multiprocessing as mp
import time
def do_soming(x):
print("do_soming begin.")
time.sleep(5)
return x**2
if __name__ == '__main__':
res_list = []
with mp.Pool(4) as p:
for i in range(10):
res = p.apply_async(do_soming, (i, ))
res_list.append(res)
# 异步apply_async用法:如果使用异步提交的任务,主进程需要使用join,
# 等待进程池内任务都处理完,然后可以用get收集结果,否则,主进程结束,
# 进程池可能还没来得及执行,也就跟着一起结束了
p.close()
p.join()
print("begin waitting.")
for res in res_list:
print(res.get())#阻塞,等等到所有的线程都返回了才会执行下一行
print("end waitting.")
print("main end.")
进一步学习请参考
https://www.cnblogs.com/freeman818/p/7154089.html
https://www.cnblogs.com/alan-babyblog/p/5351031.html
进程间的通讯
进程间的通讯有点类似生产者和消费者(一般这个举例会出现在操作系统里边),一个进程A给另外一个进程B写入数据,当B发现有数据时就输出,没有时就等待A写入;在这个过程中就用到了某个容易来临时存放数据,所以有了以下的几个小知识
Queue对象
# !/usr/bin/env python
# encoding: utf-8
import multiprocessing as mp
import time
def put_data(q, data):
print("in put_data.")
for i in data:
q.put(i)#取出元素后从Queue中删除
time.sleep(1)
def get_data(q):
print("in get_data.")
while True:
print(q.get())#如果没有数据,则会等待,可以设置timeout
if __name__ == '__main__':
q = mp.Queue()
p_list = []
data_list = [['zeng1', 'zeng2', 'zeng3', 'zeng4'],
['zeng5', 'zeng6', 'zeng7', 'zeng8'],
['zeng9', 'zeng10', 'zeng11', 'zeng12']]
put_process1 = mp.Process(target=put_data, args=(q, data_list[0]))
put_process2 = mp.Process(target=put_data, args=(q, data_list[1]))
put_process3 = mp.Process(target=put_data, args=(q, data_list[2]))
get_process = mp.Process(target=get_data, args=(q, ))
put_process1.start()
put_process2.start()
put_process3.start()
get_process.start()
put_process1.join()
put_process2.join()
put_process3.join()
time.sleep(10)
print("main end.")
get_process.terminate()
程序启动了3个put进程,对Queue写入数据,启动一个get进程从里面取出数据(死循环,自己不会退出),并没有对get进程进行join,因此主线程不会等待get进程执行完毕后再退出,因此只需要put进程结束后,就给get进程发出terminate结束信息
但是如果想使用Pool来简化进程的操作会失败,需要改成在Pool中对Queue进行初始化
参考(相当于把q保存到了全局中,不建议这么用,还是使用manager来管理):
https://blog.csdn.net/tpoy0099/article/details/50324485
# !/usr/bin/env python
# encoding: utf-8
import multiprocessing as mp
import time
def put_data(data):
print("in put_data.")
for i in data:
get_data.q.put(i)#取出元素后从Queue中删除
time.sleep(1)
def get_data(q):
print("in get_data.")
while True:
print(q.get())#如果没有数据,则会等待,可以设置timeout
def queue_init(q):
get_data.q = q
if __name__ == '__main__':
q = mp.Queue()
p_list = []
data_list = [['zeng1', 'zeng2', 'zeng3', 'zeng4'],
['zeng5', 'zeng6', 'zeng7', 'zeng8'],
['zeng9', 'zeng10', 'zeng11', 'zeng12']]
get_process = mp.Process(target=get_data, args=(q,))
p = mp.Pool(3, queue_init, (q, ))
for i in range(3):
p.apply_async(put_data, (data_list[i], ))
p.close()
get_process.start()
p.join()
time.sleep(10)
print("main end.")
get_process.terminate()
Pipe对象
Pipe也是实现进程间数据传递的一种形式,其实是使用的共享内存实现的,跟Queue差不多原理
# !/usr/bin/env python
# encoding: utf-8
import multiprocessing as mp
def child_pipe_set(child_pipe):
child_pipe.send('hello world.')#往管道中灌入数据
print(child_pipe.recv())#等待回复,会阻塞
child_pipe.close()#关闭当前管理的一端
def parent_pipe_set(parent_pipe):
print(parent_pipe.recv()) # 获取管道中的数据,会阻塞
parent_pipe.send("ok.")
parent_pipe.close() # 关闭当前管理的一端
if __name__ == '__main__':
parent_pipe, child_pipe = mp.Pipe()
child_process = mp.Process(target=child_pipe_set, args=(child_pipe, ))
parent_process = mp.Process(target=parent_pipe_set, args=(parent_pipe, ))
child_process.start()
parent_process.start()
child_process.join()
parent_process.join()
print("main end.")
Manager对象
Manager对象其实是也是一个进程,拥有list、dict、Queue等的服务器端进程,既可以在本机进行通讯,也可以在不同的电脑上进行,下面是一个使用Manager对象中Queue进行进程间数据交换的例子
# !/usr/bin/env python
# encoding: utf-8
import multiprocessing as mp
import time
def put_data(q, data):
print("in put_data.")
for i in data:
q.put(i)#取出元素后从Queue中删除
time.sleep(1)
def get_data(q):
print("in get_data.")
while True:
print(q.get())#如果没有数据,则会等待,可以设置timeout
if __name__ == '__main__':
q = mp.Manager().Queue()
data_list = [['zeng1', 'zeng2', 'zeng3', 'zeng4'],
['zeng5', 'zeng6', 'zeng7', 'zeng8'],
['zeng9', 'zeng10', 'zeng11', 'zeng12']]
get_process = mp.Process(target=get_data, args=(q, ))
get_process.start()
with mp.Pool(3) as p:
print(data_list.__len__())
for i in range(data_list.__len__()):
print(i)
p.apply_async(put_data, (q, data_list[i], ))
p.close()
p.join()
time.sleep(10)
print("main end.")
get_process.terminate()
多进程的同步
多进程的同步有某些地方会用得着,比如某个资源、某段代码同一时间有且仅能有一个进程进行使用,比如有N个进程同时需要修改队列的数据
# !/usr/bin/env python
# encoding: utf-8
import multiprocessing as mp
import os
import time
def show_info(q, num):
print("show_info, process id:{0}, num value:{1}".format(os.getpid(), num))
total = q.get()
time.sleep(2)
total += num
q.put(total)
if __name__ == '__main__':
#创建4个进程
q = mp.Queue()
total = 0
q.put(total)
start_time = time.time()
for i in range(4):
p = mp.Process(target=show_info, args=(q, i, ))
p.start()#让线程跑起来
p.join()#主线程等待
end_time = time.time()
print(q.get())
print(end_time - start_time)
print("main end.")
嗯,据说是不安全的,因为有可能在A进程修改的时候,B进程也在修改…不过可能用的是mp里面的Queue,可能不会出现这种情况(但,就假装会出现吧,不然下面没法继续了…)
Lock对象
# !/usr/bin/env python
# encoding: utf-8
import multiprocessing as mp
import os
import time
def show_info(lock, q, num):
lock.acquire()#获取锁
try:
print("show_info, process id:{0}, num value:{1}".format(os.getpid(), num))
total = q.get()
time.sleep(2)
total += num
q.put(total)
except Exception:
print(Exception)
finally:
pass
lock.release()#解开锁
if __name__ == '__main__':
#创建4个进程
q = mp.Queue()
total = 0
q.put(total)
lock = mp.Lock()#定义一个锁
start_time = time.time()
for i in range(4):
p = mp.Process(target=show_info, args=(lock, q, i, ))
p.start()#让线程跑起来
p.join()#主线程等待
end_time = time.time()
print(q.get())
print(end_time - start_time)
print("main end.")
可以看到还是有点效果的,毕竟速度慢得可以
Event对象
# !/usr/bin/env python
# encoding: utf-8
import multiprocessing as mp
import os
import time
def show_info(event, q, num):
if event.is_set():#等待时间状态为可设置
event.wait()#等待线程
try:
print("show_info, process id:{0}, num value:{1}".format(os.getpid(), num))
total = q.get()
time.sleep(2)
total += num
q.put(total)
except Exception:
print(Exception)
finally:
event.clear()
else:
event.set()#设置事件状态为可设置
if __name__ == '__main__':
#创建4个进程
q = mp.Queue()
total = 0
q.put(total)
event = mp.Event()#定义一个锁
start_time = time.time()
for i in range(4):
p = mp.Process(target=show_info, args=(event, q, i, ))
p.start()#让线程跑起来
p.join()#主线程等待
end_time = time.time()
print(q.get())
print(end_time - start_time)
print("main end.")
当然还可以利用Queue或者Pipe来做同步
https://blog.csdn.net/mydear_11000/article/details/52778619
更多进程的知识,请参阅
https://docs.python.org/3.6/library/multiprocessing.html