1、线程池的概念

  由于python中的GIL导致每个进程一次只能运行一个线程,在I/O密集型的操作中可以开启多线程,但是在使用多线程处理任务时候,不是线程越多越好,因为在线程切换的时候,需要切换上下文环境,这样会导致CPU的大量开销,同时产生大量的切换时间浪费。为了解决这个问题,线程池概念被提出。预先创建好一个较为优化的数量的线程,让过来的任务立刻能够使用,就形成了线程池。python中的concurrent.futures模块为我们做了很好地封装,该模块为我们封装了线程池和进程池。

2、最佳线程数的获取:

  1、通过用户慢慢递增来进行性能压测,观察QPS(即每秒的响应请求数,也即是最大吞吐能力。),响应时间

  2、根据公式计算:服务器端最佳线程数量=((线程等待时间+线程cpu时间)/线程cpu时间) * cpu数量

  3、单用户压测,查看CPU的消耗,然后直接乘以百分比,再进行压测,一般这个值的附近应该就是最佳线程数量。

3、concurrent.futures模块中的线程池

from concurrent.futures import ThreadPoolExecutor
import time,os
def fn(name):
    print('%s %s is running' %(name,os.getpid()))
    time.sleep(3)
if __name__=="__main__":
    p=ThreadPoolExecutor(5) #设置线程池线程数
    for i in range(10):
        obj=p.submit(fn,'线程pid:') #submit(fn, *args, **kwargs)
    res=obj.result() #注意:submit提交后返回的结果是一个future对象,需要使用obj.result才能获取想要的字符串等结果
    p.shutdown(wait=True) # 关闭线程池的入口,等待池内任务运行结束

4、concurrent.futures模块中的进程池

from concurrent.futures import ProcessPoolExecutor
import time,os
def fn(name):
    print('%s %s is running' %(name,os.getpid()))
    time.sleep(3)
if __name__=="__main__":
    p=ProcessPoolExecutor(5) #设置进程池线程数
    for i in range(10):
        obj=p.submit(fn,'进程pid:') #submit(fn, *args, **kwargs)
    res=obj.result() #注意:submit提交后返回的结果是一个future对象,需要使用obj.result才能获取想要的字符串等结果
    p.shutdown(wait=True) # 关闭进程池的入口,等待池内任务运行结束

 5、多线程的+回调函数执行

from concurrent.futures import ThreadPoolExecutor
import requests

def fetch_async(url):
    response = requests.get(url)
    return response      #返回执行结果对象


def callback(future):  
    print(future.result()) #future 相当于将上面函数执行结果对象response传递进去执行.result()方法


url_list = ['http://www.github.com', 'http://www.bing.com']
pool = ThreadPoolExecutor(5)
for url in url_list:
    v = pool.submit(fetch_async, url)
    v.add_done_callback(callback) #执行对象的回调函数
pool.shutdown(wait=True)

 

posted on 2019-05-13 21:32  赏孤舟蓑笠  阅读(291)  评论(0编辑  收藏  举报