多进程查询数据,multiprocessing模块

背景

在之前使用线程跑数据提高效率后,我进而想使用进程来跑数据,看看效率能提高多少。可能不是最好的实现方法,但是自己做个记录

之前线程的效率如下:
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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值