背景
在之前使用线程跑数据提高效率后,我进而想使用进程来跑数据,看看效率能提高多少。可能不是最好的实现方法,但是自己做个记录
之前线程的效率如下:
90000条数据,9个线程,用时28分钟
在本次使用进程后效率如下:
90000条数据,9个进程,用时5分钟
可见使用进程比线程速度提高了不少
自己使用电脑时win系统,cpu情况如下:
目的
使用进程提高效率,也是为了通过这次实践让自己对进程做一个简单的了解
参考
多进程获取函数返回值
1,共享变量Manager()实现
https://segmentfault.com/q/1010000010403117
2,进程池Pool实现
https://blog.csdn.net/haoxun02/article/details/104156829
进程模块学习
https://www.jb51.net/article/145700.htm
https://blog.csdn.net/ctwy291314/article/details/89358144
https://gaoming.blog.csdn.net/article/details/89358144
https://blog.csdn.net/sinat_35360663/article/details/78328418
一,数据库操作中加进程锁机制(与线程锁一样)
# coding = utf-8
import time
from datetime import datetime
from getlocalip import get_host_ip
import multiprocessing
import pymysql
class MyDB():
metux = multiprocessing.Lock() #使用进程的Lock()
def __init__(self,host,port,db,user,passwd):
self.host = host
self.port = port
self.db = db
self.user = user
self.passwd = passwd
try:
self.conn = pymysql.connect(
host=self.host,
port=self.port,
db=self.db,
user=self.user,
passwd=self.passwd,
charset='utf8mb4'
)
self.cur = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
except Exception as e:
print('链接数据库出错:',e)
def executesql(self, sql):
try:
with self.metux: #自动加锁解锁
self.cur.execute(sql)
sql_start = sql[:6].upper()
if sql_start == 'SELECT':
res = self.cur.fetchall()
else:
self.conn.commit()
res = '修改ok:' + sql
return res
except Exception as e:
print('链接数据库出错:',e)
def close(self):
self.cur.close()
self.conn.close()
二,进程执行并获取函数返回值
需要注意:
1,进程和线程的区别之一是:进程之间无法通信,且之间不能共享实例,所以需要使用其它方式实现
方法:
1,使用Manager共享变量,获取函数返回值(并不是按添加顺序执行并返回结果)
Manager是通过共享进程的方式共享数据,Manager管理的共享数据类型有:Value、Array、dict、list、Lock、Semaphore等等,同时Manager还可以共享类的实例对象。
# coding=utf-8
import multiprocessing
from multiprocessing import Manager
def return_something(start,end):
res=[]
res.append(start)
res.append(end)
return res
def run_process(start,end,return_dict):
res=return_something(start,end)
return_dict[start]=res #将拿到的结果加入到return_dict字典中
def run():
#使用Manager共享变量
manager = Manager()
return_dict = manager.dict()
result = []
process = []
for i in range(1,5):
start = (i - 1) * 1000 + 1
end=i*1000
p = multiprocessing.Process(target=run_process, args=(start,end,return_dict))
p.start()
process.append(p)
for t in process:
t.join() # 一定执行join,等待子进程执行结束,主进程再往下执行
for res in return_dict.values():
result +=res #将每个进程的结果组合到一起
print("result:",result)
if __name__ == '__main__':
run()
#结果:每次打印出来的顺序都不一样
result: [1001, 2000, 1, 1000, 3001, 4000, 2001, 3000]
2,使用进程池Pool并拿到函数返回结果(结果按添加顺序执行并返回结果)
Pool常用方法:
apply_async(func,args)
从进程池中取出一个进程执行func,args为func的参数。它将返回一个AsyncResult的对象,你可以对该对象调用get()方法以获得结果。
close()
进程池不再创建新的进程
join()
wait进程池中的全部进程。必须对Pool先调用close()方法才能join。
map()
将f()函数作用到表的每个元素上。这与built-in的map()函数类似
# coding=utf-8
import multiprocessing
from multiprocessing import Pool
def return_something(start,end):
res=[]
res.append(start)
res.append(end)
print(res)
return res
def run():
pool = multiprocessing.Pool(processes=4) #开4个进程
pool_res=[]
result = []
for i in range(1,5):
start = (i - 1) * 1000 + 1
end=i*1000
res=pool.apply_async(return_something,(start,end,))
pool_res.append(res)
pool.close()
pool.join() #join方法,使主进程等待
for res in pool_res:
result +=res.get() #将每个进程的结果组合到一起
print("result:",result)
if __name__ == '__main__':
run()
#结果:每次打印出来的顺序都一样
result: [1, 1000, 1001, 2000, 2001, 3000, 3001, 4000]
3,使用multiprocessing模块的Process(使用方式和线程一样)
注意:Process对象只能在在 if name == ‘main’:下创建,不然会报错:
TypeError: cannot serialize ‘_io.BufferedReader’ object