美文网首页
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