python多进程与多线程

互联网上介绍多进程的文章很多,比如Python多进程 - 实现多进程的几种方式python多进程并发多进程。为什么自己记录呢,是因为在做多进程的时候总会遇到这样那样的问题,故只好亲自实践一下。
1 最简单的多进程
使用multiprocessing.Process定义进程,target参数传递的是进程执行的方法,args则是传递给执行方法的参数,这个参数不要太复杂,复杂类型就可能会报错。

import multiprocessing
if __name__ == '__main__':
    sub_list = get_sub_list()
    p0 = multiprocessing.Process(target=to_total, args=(sub_list[0],))
    p1 = multiprocessing.Process(target=to_total, args=(sub_list[1],))
    # 开启进程
    p0.start()
    p1.start()
    # 阻塞进程
    p0.join()
    p1.join()

执行中,可以在windows任务管理器中看到两个python进程在运行了。从监控中,也可以看到问题。我们知道进程是资源分配的最小单位,而python启动两个进程后,CPU、内存基本没什么消耗,而我是处理几万的数据,那么怎样让CPU忙碌起来呢?及时启动再多进程也没有办法,因为我的业务逻辑是读取两个es索引的数据,进行处理,我还不能防止重复。
1
2 多进程(生产者-消费者模式)
难道真的没有办法吗?“线程是CPU调用的最小单位”,是否可以利用线程提供资源利用率呢?多线程还是多进程的选择及区别
python并发编程之多进程、多线程、异步和协程,从这些文章可以看出来,如果我想采用多进程、多线程的编程模式,我的代码逻辑必须调整。
原先简单的多进程逻辑to_total的代码逻辑是

# 从es中分片读取数据
# 将读取后的数据进行业务处理并存入到数据库中

但看了为什么在Python里推荐使用多进程而不是多线程?Python中单线程、多线程和多进程的效率对比实验,在python中使用多进程比多线程要好。那么我是不是可以利用生产者-消费者模式,做多进程呢?
代码并不难,仿照python并发编程:多进程-生产者消费者模型,写了一个:

'''
多进程(生产者-消费者)
'''
import time
import random
import pymongo
from elasticsearch import Elasticsearch
from elasticsearch import helpers
from redis.sentinel import Sentinel
from multiprocessing import Process, JoinableQueue

def consumer(q,i):
    '''
    消费者
    :return: 
    '''
    print('消费进程%d启动' % i)
    es = get_es()
    mongo = get_mongo()
    esService = getEsService(es,mongo)
    while True:
        item = q.get()
        print('消费进程%d数据' % i)
        time.sleep(random.randint(1, 3))
        esService.handler(item)
        q.task_done()

def producer(q,sub_index):
    '''
    生产者
    :return: 
    '''
    #
    print('生产进程%s启动' % sub_index)
    es = get_es()
    #
    body = {
        "query": {
            "match_all": {
            }
        }}
    results = helpers.scan(
        client=es,
        query=body,
        scroll="5m",
        index=sub_index,
        doc_type='test_type',
        timeout="10m"
    )
    for result in results:
        name = result.get('_source').get('name')
        date = result.get('_source').get('date')
        source = result.get('_source').get('source')
        item = {'name': name,
                'date': date, 'source': source}
        if 'status' in result.get('_source'):
            item['status'] = result.get('_source').get('status')
        q.put(item)
    q.join()

def get_es():
    if ES_USER:
        es = Elasticsearch([ES_IP], http_auth=(ES_USER, ES_PASSWORD),
                           port=9200, timeout=50000,
                           sniff_on_start=True, sniff_on_connection_fail=True, max_retries=3, retry_on_timeout=True)
    else:
        es = Elasticsearch([ES_IP], sniff_on_start=True, sniff_on_connection_fail=True,
                           max_retries=3,
                           retry_on_timeout=True)
    return es

def get_mongo():
    mongo_url = 'mongodb://10.101.3.190:27017'
    mongo = pymongo.MongoClient(mongo_url)
    return mongo

def getEsService(es, mongo):
    # reids
    params = {'db': 1}
    sentinel = Sentinel(REDIS_SENTINELS, **params)
    server = sentinel.master_for(REDIS_PARAMS['service_name'], **params)
    bot_name = 'en_total'
    # es
    return EsService(es=es,mongo=mongo['en_invalid'],redis=server)

def get_sub_list():
    sub_list = []
    sub_list.append('test01')
    sub_list.append('test02')
    sub_list.append('test03')
    sub_list.append('test04')
    sub_list.append('test05')
    sub_list.append('test06')
    return sub_list

if __name__ == '__main__':
    q = JoinableQueue()
    sub_list = get_sub_list()
    ps = []
    for sub in sub_list:
        p = Process(target=producer,args=(q,sub))
        ps.append(p)
    # 生产者启动
    for p in ps:
        p.start()
    # 消费者启动
    cs = []
    for i in range(20):
        c = Process(target=consumer, args=(q,i ))
        c.daemon = True
        cs.append(c)
    for c in cs:
        c.start()
    # 生产者阻塞
    for p in ps:
        p.join()

运行成功
1
但是在资源管理器中查看,为什么进程消耗的CPU为0呢?
2
3 进程池
参考python3.x pool.map方法的实质,关于性能的描述可以参考
python 性能提升之 并行map

import multiprocessing
    pool = multiprocessing.Pool(processes=multiprocessing.cpu_count())
    pool.map(cal_each, [row for ix, row in df.iterrows()])
    pool.close()
    pool.join()

def cal_each(row):
	pass

4 多线程
Process Explorer v16.43
安装过程参考windows查看线程工具
Python 异步 IO(asyncio)、多进程(multiprocessing)、多线程(multithreading)性能对比
1

from life_example.service.example_service import ExampleService
import asyncio
import multiprocessing

async def parse_bazi(bazi):
    print(bazi)
    gzShishen = parse(bazi)
    exampleService.save_gz_shishen(gzShishen)

def parse_with_process(day):
    bazis = exampleService.get_bazi_by_day(day)
    loop = asyncio.get_event_loop()
    tasks = []
    for bazi in bazis:
        tasks.append(parse_bazi(bazi))
    loop.run_until_complete(asyncio.wait(tasks))

def run_by_process():
    day_list = ['甲子','乙丑','丙寅','丁卯','戊辰','己巳','庚午','辛未','壬申','癸酉']
    pool = multiprocessing.Pool(processes=multiprocessing.cpu_count())
    result = pool.map(parse_with_process,day_list)
    print(result)
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

warrah

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值