美文网首页
python多进程

python多进程

作者: 清水秋香 | 来源:发表于2020-03-23 17:02 被阅读0次

    并发与并行
    并发和并行是两个非常容易混淆的概念。他们都可以表示两个或多个任务一起执行,但是偏重点有点不同。并发偏重于多个任务交替执行,而多个任务之间有可能还是串行的。并发是逻辑上的同时发生,而并行是物理上的同时发生,然而并行的偏重点在于同时执行。
    并发:指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在宏观上具有多个进行同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个进程快速交替的执行。这就能好比一个人一把铁锹同时挖三个坑,每个坑都挖一下然后去挖下一个,虽然三个坑都变大,但实际上同一时间只有一个坑在被挖。
    严格意义上来说,并行的多个任务是真实的同时执行,而对于并发来说,这个过程只是交替的,一会运行任务一,一会运行任务二,系统会不停的在两者间切换,对于外部观察者来说,即使多个任务是串行并发的,也会造成多个任务并行执行的错觉。
    并行,指在同一时刻,有多条指令在多个处理器上同时执行,就好像三个人三把铁锹同时在挖三个坑,三个坑一起变大,所以无论从微视还是宏观来看,二者都是一起执行的。

    线程与进程
    开个qq,开了一个进程;开个迅雷,开了一个进程
    在qq的这个进程里,传输文字开一个线程。在这个软件运行的过程(在这个进程里),多个工作同时运转,完成了qq的运行,那么这“多个工作”分别有一个线程,所以一个进程管着多个线程,一个进程有且至少有一个线程

    • 多进程不共享全局变量
    from multiprocessing import Process
    import time
    
    a = 100
    def work1():
        for i in range(10):
            global a
            print('这个是任务1-----{}'.format(a))
            a += 1
            time.sleep(0.5)
    
    
    def work2():
        for i in range(10):
            global a
            print('这个是任务2----{}'.format(a))
            a+=1
            time.sleep(0.5)
    
    #多进程执行多任务
    #创建两个进程
    p1 = Process(target=work1)
    p2 = Process(target=work2)
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    
    
    • 解决多进程之间通信问题
    import time
    
    # from queue import Queue
    #queue.Queue是进程内非阻塞队列
    #multipprocess.Queue是跨进程通信队列
    #多进程前者是各自私有,后者是各子进程共有
    #process之间有时需要通信,操作系统提供了很多机制来实现进程间的通信
    
    #创建一个队列添加10个任务
    
    from multiprocessing import Process,Queue
    import os, time, random
    # 写数据进程执行的代码:
    def write(q):
        for value in ['A', 'B', 'C']:
            print('Put %s to queue...' % (value))
            q.put(value)
            time.sleep(random.random())
    
    # 读数据进程执行的代码:
    def read(q):
        while True:
            if not q.empty():
                value = q.get(True)
                print('Get %s from queue.' % (value))
                time.sleep(random.random())
            else:
                break
    
    if __name__=='__main__':
        # 父进程创建Queue,并传给各个子进程:
        q = Queue()
        pw = Process(target=write, args=(q,))
        pr = Process(target=read, args=(q,))
        # 启动子进程pw,写入:
        pw.start()
        # 等待pw结束:
        pw.join()
        # 启动子进程pr,读取:
        pr.start()
        pr.join()
        # pr进程里是死循环,无法等待其结束,只能强行终止:
        print('所有数据都写入并且读完')
    

    进程池参数介绍

    • apply_async:使用非阻塞的方式调用func(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程),args为传递给func的参数列表,kwds为传递给func的
      关键字参数列表
    • close:关闭Pool,使其不在接受新的任务
    • terminate:不管任务是否完成,立即终止
    • join:主进程阻塞,等待子线程的退出,必须在close或terminate之后使用;

    进程池的使用

    from multiprocessing import Pool,Manager
    import os
    a = 0
    def read1(q):
        q.get()
        a = 0
        for i in range(100000):
            a = a + 1
        print(a)
        print('Get %s from queue.' % (os.getpid()))
        # time.sleep(random.random())
    
    if __name__ == '__main__':
        q = Manager().Queue()
        pool = Pool(10)
        for value in range(100):
            q.put(value)
        for i in range(100):
            if not q.empty():
                # print('haha')
                pool.apply_async(func=read1,args=(q,))
            else:
                break
    
        pool.close()
        pool.join()
    
    • 1000个I/O任务分别使用3个进程和3个线程来完成,哪个更快
    #进程快
    #做多任务的时候进程快,只用进程不合理,进程占用资源大,应进程里面开线程,线程里面开协程
    import os
    import queue
    import time
    from multiprocessing import Manager,Pool
    from threading import Thread
    #线程的队列(只能在一个进程中使用)
    import requests
    
    
    
    # requests.get('http://www.apple.com/') 
    #如果是mac电脑需要打开此行注释方可运行,否则在进行网络请求的时候会卡住。
    
    X = 0
    def work(q3):
        while not q3.empty():
            url = q3.get()
            print('xxx')
            requests.get(url= url)
            print('ooo')
            global X
            X += 1
            print(X)
    
        print('该进程运行了%s次'%(X))
    
    if __name__ == '__main__':
        q3 = Manager().Queue()
        for i in range(1000):
            q3.put('https://www.apple.com/')
        pool = Pool(3)
        st = time.time()
        for i in range(3):
            pool.apply_async(work,args=(q3,))
        #关闭进程池,停止往进程池中添加新的任务
        pool.close()
        #主进程等待,子进程结束在进行
        pool.join()
        et = time.time()
        print('耗时{}',format(et-st))
    #     #耗时{} 30.68186616897583
    
    
    # def main():
    #     q = queue.Queue()
    #     for i in range(1000):
    #         q.put('https://www.apple.com/')
    #     st = time.time()
    #     t1 = Thread(target=work,args=(q,))
    #     t2 = Thread(target=work,args=(q,))
    #     t3 = Thread(target=work,args=(q,))
    #     t1.start()
    #     t2.start()
    #     t3.start()
    #     t1.join()
    #     t2.join()
    #     t3.join()
    #     et = time.time()
    #     print('耗时',et-st)
    # if __name__ == '__main__':
    #     main()
        # 线程 耗时 35.74414277076721
    
    
    • 1000个计算密集型任务线程、进程之间的比较
      很明显计算密集型任务,因为GIL锁的存在python线程并不占优势
    import time
    from multiprocessing import Manager,Pool
    import requests
    X = 0
    def work(q3):
        while not q3.empty():
            q3.get()
            a = 0
            for i in range(100000):
                a = a + i
            print(a)
            global X
            X += 1
        print('该进程运行了%s次'%(X))
    
    if __name__ == '__main__':
        q3 = Manager().Queue()
        for i in range(10000):
            q3.put(i)
        pool = Pool(3)
        st = time.time()
        for i in range(3):
            pool.apply_async(work,args=(q3,))
        #关闭进程池,停止往进程池中添加新的任务
        pool.close()
        #主进程等待,子进程结束在进行
        pool.join()
        et = time.time()
        print('耗时{}',format(et-st))
        # 耗时{} 19.595630168914795
    
    
    import time
    from threading import Thread
    from queue import Queue
    X = 0
    def work(q):
        while not q.empty():
            q.get()
            a = 0
            for i in range(100000):
                a = a + i
            print(a)
            global X
            X += 1
    if __name__ == '__main__':
            q = Queue()
            for i in range(10000):
                q.put(i)
            t1 = Thread(target=work,args=(q,))
            t2 = Thread(target=work,args=(q,))
            t3 = Thread(target=work,args=(q,))
            st = time.time()
            t1.start()
            t2.start()
            t3.start()
            t1.join()
            t2.join()
            t3.join()
            et = time.time()
            print('线程执行时间%s'%(et-st))
            #线程执行时间55.236459732055664
    
    

    进程在进行计算密集型任务时体现出了极大的优势,并且进程是可以完成并行的,但是进程占用的资源也是极大的,使用的时候要考虑资源消耗。

    相关文章

      网友评论

          本文标题:python多进程

          本文链接:https://www.haomeiwen.com/subject/pfwwyhtx.html