[Python 多线程] multiprocessing、多进程、工作进程池 (十四)

 

由于Python的GIL限制,多线程未必是CPU密集型程序的好的选择。

多进程可以完全独立的进程环境中运行程序,可以充分地利用多处理器。

但是进程本身的隔离性带来的数据不共享也是一个问题。而且线程比进程轻量级。

 

multiprocessing

Process类

Process类遵循了Thread类的API,减少了学习难度。(几乎和Thread类使用方法一模一样) 

 

 

 

上一篇文章里最后使用了多线程来解决CPU密集型的例子,但发现多线程和多线程最终执行效率几乎相同,多线程并没有想象中的优势。

上一篇中多线程的例子:

#模拟CPU密集型 多线程
import threading,logging,time,random,datetime
DATEFMT="%H:%M:%S"
FORMAT = "[%(asctime)s]\t [%(threadName)s,%(thread)d] %(message)s"
logging.basicConfig(level=logging.INFO,format=FORMAT,datefmt=DATEFMT)


def calc():
    sum = 0
    for _ in range(100000000):
        sum += 1

start =datetime.datetime.now()

t1 = threading.Thread(target=calc)
t2 = threading.Thread(target=calc)
t3 = threading.Thread(target=calc)
t4 = threading.Thread(target=calc)
t5 = threading.Thread(target=calc)

t1.start()
t2.start()
t3.start()
t4.start()
t5.start()

t1.join()
t2.join()
t3.join()
t4.join()
t5.join()


print('aaa')
delta = (datetime.datetime.now() -start).total_seconds()
print(delta)

#运行结果:
aaa
53.135543

  此例子是单线程情况下执行耗时58秒左右。

再使用多进程的例子来看一下是否可以有所不同:

#=========多进程、真正的并行、适用于CPU计算密集型===============
import multiprocessing
import datetime

def calc(i):
    sum = 0
    for _ in range(100000000):
        sum += 1
        # print(i,sum)

if __name__ == "__main__":
    start = datetime.datetime.now()
    lst = []

    for i in range(5):
        p = multiprocessing.Process(target=calc,args=(i,),name='p-{}'.format(i))
        p.start()
        lst.append(p)

    for p in lst:
        p.join()

    delta = (datetime.datetime.now() - start).total_seconds()
    print(delta)

运行结果:
24.767709

  从耗时结果可以看出多线程的执行效率明显得要比多线程(其实就是单线程)高得多。

 

进程间同步:

 进程间同步提供了和线程同步一样的类,使用方法一样,使用的效果也类似。

不过,进程间代价要高于线程,而且底层😡实现是不同的,只不过Python屏蔽了这些,让用户简单使用。

 

multiprocessing还提供共享内存、服务器进程来共享数据,还提供了Queue队列、Pipe管道用于进程间通信。

 

通信方式不同:

多线程就是启动多个解释器进程,进程间通信必须序列化、反序列化

数据的线程安全性问题

  由于每个进程中没有实现多线程,GIL可以说没什么用了。

 

进程池举例:

进程池只能由创建它的进程使用

# 进程池

import multiprocessing
import datetime

def calc(i):
    sum = 0
    for _ in range(100000000):
        sum += 1

if __name__ == "__main__":
    start = datetime.datetime.now()

    pool = multiprocessing.Pool(5) #定义同时至多起几个线程
    for i in range(5):
        pool.apply_async(calc,args=(i,))

    pool.close()
    pool.join()

    #多线程
    # lst = []

    # for i in range(5):
    #     p = multiprocessing.Process(target=calc,args=(i,),name='p-{}'.format(i))
    #     p.start()
    #     lst.append(p)
    #
    # for p in lst:
    #     p.join()

    delta = (datetime.datetime.now() - start).total_seconds()
    print(delta)

运行结果:
24.944169

  

 

多进程、多线程的选择

1、CPU密集型

CPython中使用到了GIL,多线程的时候锁相互竞争,且多核优势不能发挥,Python多进程效率更高。

2、IO密集型

适合是用多线程,减少IO序列化开销。且在IO等待的时候,切换到其它线程继续执行,效率不错。

 

应用:

请求/应答模型:WEB应用中常见的处理模型

 

master启动多个worker工作进程,一般和CPU数目相同。

worker工作进程中启动多线程,提高并发处理能力。worker处理用户的请求,往往需要等待数据。

这就是nginx工作模式。

 

posted @ 2017-12-21 16:27  ihoneysec  阅读(1772)  评论(0编辑  收藏  举报