使用模块
multiprocessing
简单例子
import multiprocessing
def test(n):
name = multiprocessing.current_process().name
print(name,"starting")
print("is",n)
return
if __name__ == '__main__':
num_list =[]
for i in range(10):
p = multiprocessing.Process(target=test,args=(i,))
num_list.append(p)
p.start()
#join是阻塞主进程等待子进程返回
p.join()
print(multiprocessing.cpu_count())
print("End")
print(num_list)
上面的例子中使用multiprocessing中的Process来创建进程,target为执行的方法,传入函数,args为方法需要传入的参数,此外还可设置group,name等,group一般不会用到,join为阻塞主进程,cpu_count()来获取copu的核数。name来命名子进程。进程有创建,就绪,运行,阻塞与结束共5个状态,start()方法为就绪并不是运行,告知CPU让系统来进行调度安排。
进程池的使用
from multiprocessing import Pool
def func(n):
return n**2
if __name__ == '__main__':
pool = Pool(processes=4)
#异步非阻塞
result = pool.apply_async(func,[10])
print(result.get(timeout=1))
print(pool.map(func,range(10)))
processes意思为开4个进程,一个cpu开一个进程,apply_async为异步启动,如一个任务有4个步骤,使用异步的话就不需要按顺序执行,执行1的同时可以执行2,不需要等待。进程池里还有close()和join()、map()等方法,close()为禁止往进程池添加任务,join()与普通的多进程相仿,map(func,iterate)与python中的map一样迭代队列执行func。
多进程队列
from multiprocessing import Process,Queue
def set_data(queue):
for i in range(10):
queue.put("hello"+str(i))
def get_data(queue):
for i in range(10):
print(queue.get())
if __name__ == '__main__':
q = Queue()
p1 = Process(target=set_data,args=(q,))
p2 = Process(target=get_data,args=(q,))
p1.start()
p2.start()
p1.join()
p2.join()
print("空...空了吗?",q.empty())
一个进程往队列添加数据,一个进程取走数据,使用这种方法在爬虫之中,可以一个进程存储未爬取的url,一个进程获取,来提高爬取数据的速度。
进程锁
from multiprocessing import Process,Lock,Semaphore
def test_lock(lock,n):
lock.acquire()#获得锁
print("this is ",n)
lock.release()#最后解锁释放
if __name__ == '__main__':
lock = Lock()
# s = Semaphore(3)
for i in range(10):
Process(target=test_lock,args=(lock,i)).start()
在多进程中,可能在同一时间对一个变量进行访问修改,这时候需要加把锁来锁住,防止一边在修改并且提交了修改后的数据,另一边访问到未修改前的数据并对其修改。加锁可以保证数据的稳定性与安全性,multiprocessing中有2种方式加锁,一种是Lock,一种是Semaphore,后者可以设置同时多少个进程进行访问。
消息传递
from multiprocessing import Process,Event
def wait(event):
print("wait~~~")
event.wait()
print("event.is_set",event.is_set())
def wait_timeout(event,t):
print("timeout!!!")
print()
print("event.is_set", event.is_set())
event.set()#设置为真
if __name__ == '__main__':
event = Event()
print(event.is_set())
t1 = Process(target=wait,args=(event,))
t1.start()
t2 = Process(target=wait_timeout,args=(event,2))
t2.start()
print("set event")
在multiprocessing中可以使用Event来进行进程间的通讯,通过is_set()方法来获取当前状态来进行下一步的操作,wait()方法为阻塞等待,如果未接到可执行信号时将一直阻塞。timeout()顾名思义则是超时设置,在超过多少时间后进行信号的设置,然后进行下一步的操作。可以把wait_timeout中的event.set()注释掉来查看具体的效果。
管道
from multiprocessing import Process,Pipe
def p1(pipe):
pipe.send('pipe1')
print("pipe1 received: %s"%pipe.recv())
pipe.send("who are you")
print("pipe1 received: %s"%pipe.recv())
def p2(pipe):
pipe.send('pipe2')
print("pipe2 received: %s"%pipe.recv())
pipe.send("this is a bad problem")
print("pipe2 received: %s"%pipe.recv())
if __name__ == '__main__':
pipe = Pipe()
#第一个管道对象传入第一个进程
process1 = Process(target=p1,args=(pipe[0],))
# 第二个管道对象传入第二个进程
process2 = Process(target=p2,args=(pipe[1],))
process1.start()
process2.start()
process1.join()
process2.join()
管道可以看做是两个进程之间进行消息的互通,可以设置单向管道,默认为双向的管道,管道的端口智能由一个进程来使用,否则出现错误。用send来发送消息,recv来接收消息。
多进程共享变量
from multiprocessing import Process,Value,Array
def func(n,a):
n.value = 200
for i in range(len(a)):
a[i] = -a[i]
if __name__ == '__main__':
num = Value('d',0.0)
print(num.value)
arr = Array('i',range(10))
print(arr[:])
p = Process(target=func,args=(num,arr))
p.start()
p.join()
print(num.value)
print(arr[:])
在multiprocessing中使用Value和Array来进行变量的共享,value是创建变量大小的共享内存,Array是创建数组大小的共享内存,第一个参数为创建的类型。进程之中的变量为独立的,而num和arr为主进程的变量,通过Value和Array,可以在子进程中进行修改。