• Python多进程


    多进程

    由于GIL(全局解释锁)的问题,多线程并不能充分利用多核处理器,如果是一个CPU计算型的任务,应该使用多进程模块 multiprocessing 。它的工作方式与线程库完全不同,但是两种库的语法和接口却非常相似。multiprocessing给每个进程赋予单独的Python解释器,这样就规避了全局解释锁所带来的问题。

    import time
    import multiprocessing
    from multiprocessing.pool import Pool
    from multiprocessing.dummy import Pool as ThreadPool
    
    def profile(func):
        def wrapper(*args, **kwargs):
            import time
            start = time.time()
            func(*args, **kwargs)
            end = time.time()
            print('COST: {}'.format(end - start))
        return wrapper
    
    def fib(n):
        if n <= 2:
            return 1
        return fib(n - 1) + fib(n - 2)
    
    @profile
    def nomultiprocess():
        fib(35)
        fib(35)
    
    @profile
    def hasmultiprocess():
        jobs = []
        for i in range(2):
            p = multiprocessing.Process(target=fib, args=(35,))
            p.start()
            jobs.append(p)
    
        for job in jobs:
            job.join()
    
    if __name__ == '__main__':
        nomultiprocess()
        hasmultiprocess()
    

    进程池

    from multiprocessing import Pool
    pool = Pool(2)  #默认启动的进程/线程数都为CPU数,如果python获取不到CPU数则默认为1
    result=pool.map(fib, [35] * 2)
    
    或者:
    result=[]
    for n in [35,35]:
        result.append(pool.apply(fib, n) )
    

    线程池

    如果分不清任务是CPU密集型还是IO密集型,就用如下2个方法分别试:

    from multiprocessing import Pool
    from multiprocessing.dummy import Pool
    

    哪个速度快就用那个。从此以后尽量在写兼容的方式,这样在多线程/多进程之间切换非常方便。

    如果一个任务拿不准是CPU密集还是I/O密集型,且没有其它不能选择多进程方式的因素,现在都统一直接用多进程。

    进程间通信

    Queue

    多线程有Queue模块实现队列,多进程模块也包含了Queue类,它是线程和进程安全的。

    进程的Queue类并不支持task_done和join方法,需要使用特别的JoinableQueue。

    import random
    import time
    from multiprocessing import Process, Queue, JoinableQueue
    
    
    def double(n):
        return n * 2
    
    
    def producer(in_queue):
        while True:
            wt = random.random()
            in_queue.put((double, wt))
            print('produce: ', wt)
            time.sleep(wt)
    
            if wt > 0.9:
                in_queue.put(None)
                print('stop producer')
                break
    
    
    def consumer(in_queue, out_queue):
        while True:
            task = in_queue.get()
            if task is None:
                break
    
            func, arg = task
            result = func(arg)
            print('consumer result: ', result)
    
            out_queue.put(result)
            in_queue.task_done()
    
    
    if __name__ == '__main__':
        tasks_queue = JoinableQueue()  # 进程类的Queue不支持join与task_done方法
        results_queue = Queue()
        processs = []
    
        p = Process(target=producer, args=(tasks_queue,))
        p.start()
        processs.append(p)
    
        p = Process(target=consumer, args=(tasks_queue, results_queue))
        p.start()
        processs.append(p)
    
        tasks_queue.join()
    
        for p in processs:
            p.join()
    
        while results_queue.qsize() > 0:
            print(results_queue.get())
    
    

    生产者已经不会持续的生产任务了,如果随机到的结果大于0.9就会给任务队列tasks_queue put一个None,然后把循环结束掉

    消费者如果收到一个值为None的任务,就结束,否则执行从tasks_queue获取的任务,并把结果put进results_queue

    生产者和消费者都结束后(有join方法保证),从results_queue挨个获取执行结果并打印出来

    Pipe

    Pipe返回的是管道2边的对象:「父连接」和「子连接」

    def f(conn):
        conn.send(['hello'])
        conn.close()
    
    parent_conn, child_conn = Pipe()
    
    if __name__ == '__main__':
        p = Process(target=f, args=(child_conn,))
        p.start()
        p.join()
    
        print(parent_conn.recv())
    

    当子连接发送一个带有hello字符串的列表,父连接就会收到,所以 parent_conn.recv()就会打印出来。

  • 相关阅读:
    hadoop 安装、命令
    Spring Boot 中 Web 应用的统一异常处理
    处理json的常用java类库:Json-lib(org.json)、Gson、Jackson、Fastjson
    Spring Boot 项目在 IntelliJ IDEA 中配置 DevTools 实现热部署(macOS 系统)
    spring boot 项目文件结构
    3种web会话管理方式:基于server端session方式、cookie-based方式、token-based方式
    软件行业术语
    spring boot中,jar包、war包的区别
    vue-echarts-v3 使用
    Map 的营救;使对象属性有顺序
  • 原文地址:https://www.cnblogs.com/liubiao/p/6826049.html
Copyright © 2020-2023  润新知