Python学习 之 池的概念

文章目录

  • 理论知识点
  • 进程池
    • 异步调用示例(默认)
    • 同步调用示例(了解即可)
  • map的用法
  • map 的 add_done_callback()用法
  • GIL锁 -- 全局解释器锁


理论知识点

  • 同步调用和异步调用

    • 同步: 提交完任务后, 就在原地等待, 等待任务结束完毕, 拿到任务的返回值, 才能执行下一行代码, 导致程序变为串行
    • 异步: 提交完任务后, 触发回调函数的执行
  • 阻塞和非阻塞


进程池

异步调用示例(默认)

from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time, random, os


def task(n):
    print("%s is running" % os.getpid())
    time.sleep(random.randint(1, 3))
    return n**2


def handle(r):
    print("handle res %s" % r.result())


if __name__ == "__main__":
    p = ProcessPoolExecutor(3) # 参数和机器 cpu 核数相同即可

    # 默认都是异步调用
    for i in range(5):
        p.submit(task, i).add_done_callback(handle)
        
    # 相当于 join()    
    p.shutdown()

    print("main end")
    

同步调用示例(了解即可)

from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time, random, os


def task(n):
    print("%s is running" % os.getpid())
    time.sleep(random.randint(1, 3))
    return n**2


def handle(r):
    print("handle res %s" % r)


if __name__ == "__main__":
    p = ProcessPoolExecutor(3) # 参数和机器 cpu 核数相同即可


    for i in range(5):
    	# 每次开进程都需要等拿到结果 r, 并且处理
        r = p.submit(task, i).result()
        handle(r)

    # 相当于 join()    
    p.shutdown()

    print("main end")

import time
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor # 线程池, 进程池

def func(num):
    time.sleep(1)
    print(num)


if __name__ == '__main__':
    pool = ThreadPoolExecutor(20) # 池中有20个线程
    # pool = ProcessPoolExecutor(20) # 池中有20个进程
    for i in range(100):
        pool.submit(func, i)

from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
import time, random, os


def task(n):
    print("%s is running" % os.getpid())
    time.sleep(random.randint(1, 3))
    return n**2

if __name__ == "__main__":
    p = ProcessPoolExecutor(2) # 参数和机器 cpu 核数相同即可

    for i in range(5):
        p.submit(task, i)

    # p.shutdown(wait=True)

	# 如果后续还有还有其他操作, 需要阻塞池, 需要添加shutdown()方法
    pool.shutdown()

map的用法

import time,random
from concurrent.futures import ThreadPoolExecutor # 线程池


def task(n):
    print(n)
    time.sleep(random.randint(1,3)) # 模拟处理线程时间不同
    return n**2


if __name__ == '__main__':
    pool = ThreadPoolExecutor(max_workers=3) # 池中最多有三个线程
    pool.map(task, range(1,12)) # map(func, iterable)
    

map 的 add_done_callback()用法

import time,random
from concurrent.futures import ThreadPoolExecutor


url_list = [
    'http://www.baidu.com',
    'http://www.g.cn',
    'http://www.qq.com'
]


# 模拟分析网页操作
def analies(content):
    print(content.result())
    print('分析完成')


# 获取url
def get_url(url):
    time.sleep(random.uniform(1,3))
    return url


t = ThreadPoolExecutor(3) # 进程池中最多3个
for url in url_list:
    """
    线程调用get_url方法, 并且将analies方法的返回值作为参数传给get_url
    """
    t.submit(get_url, url).add_done_callback(analies)
    

GIL锁 – 全局解释器锁

  • cpython 解释器的特性, 并非 python 的
  • 在同一时刻同一进程, 只能有一个线程被cpu执行, 用来保证数据安全(牺牲多核优势)
  • GIL 锁保证的是 python 解释器的使用唯一
  • IO 等待时, 会被系统强制释放 GIL 锁, 被另一线程拿到, 执行另一线程的工作
    所以若程序为高IO型, GIL锁机制并没有太多影响, 因为全是IO等待…
  • 高计算型是需要大量访问cpu进行计算, 而python的多线程限制了这一点, 所以python并没有优势

你可能感兴趣的:(Python)