操作系统-池+回调函数

有多少个任务就开多少个进程或者线程
什么是池
要在程序开始的时候,还没提交任务先创建几个线程或者进程
放在一个池子里,这就是池
为什么要用池
如果先开好进程/线程,那么有任务之后就可以直接使用这个池中的数据了
并且开好的线程或者进程一直存在在池中,可以被多个任务反复利用,极大减少了开启或者
关闭调度线程/进程的时间开销
池中的线程/进程个数决定了操作系统需要调度的任务个数,控制池中的单位
有利于提高操作系统的效率,减轻操作系统的负担

 from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
from threading import current_thread
import time
import random


def func(a, b):
    print(current_thread().ident, 'start')
    time.sleep(random.randint(1, 4))
    print(current_thread().ident, 'end')


tp = ThreadPoolExecutor(4)  # 控制一次只能执行四个线程
for i in range(10):
    tp.submit(func, i, b=i + 1)
实例化 创建池
向池中提交任务,submit传参数(按照位置传,按照关键字传)


进程池概念
import os
from threading import current_thread
import time
import random
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor


def func(a, b):
    print(os.getpid(), 'start', a, b)
    # time.sleep(random.randint(1, 4))
    print(os.getpid(), 'end')


if __name__ == '__main__':
    tp = ProcessPoolExecutor(4)  # 控制一次只能执行四个线程
    for i in range(10):
        tp.submit(func, i, b=i + 1)

获取任务结果

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


def func(a, b):
    print(os.getpid(), 'start', a, b)
    time.sleep(random.randint(1, 4))
    print(os.getpid(), 'end')
    return a * b


if __name__ == '__main__':
    tp = ProcessPoolExecutor(4)  # 控制一次只能执行四个线程
    future_lst = {}
    for i in range(10):
        ret = tp.submit(func, i, b=i + 1)
        future_lst[i] = ret
        # print(ret.result())  # Future 未来对象
    for key in future_lst:  # 同步的
        print(key, future_lst[key].result())

map 只适合传递简单的参数,并且是一个可迭代的类型作为参数

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


def func(a):
    print(os.getpid(), 'start', a)
    time.sleep(random.randint(1, 4))
    print(os.getpid(), 'end')
    # return a * b


if __name__ == '__main__':
    tp = ProcessPoolExecutor(4)  # 控制一次只能执行四个线程
    ret = tp.map(func, range(20))
    for key in ret:  # 同步的
        print(key)

回调函数

import os
import time, random
# from threading import current_thread
# from concurrent.futures import ThreadPoolExecutor
#
#
# def func(a, b):
#     print(current_thread().ident, 'start', a, b)
#     time.sleep(random.randint(1, 4))
#     print(current_thread().ident, 'end')
#     return a * b
#
#
# def print_func(ret):
#     print(ret.result())
#
#
# if __name__ == '__main__':
#     tp = ThreadPoolExecutor(4)
#     future_l = {}
#     for i in range(20):
#         ret = tp.submit(func, i, b=i + 1)
#         ret.add_done_callback(print_func)  # 异步阻塞,回调函数给ret对象绑定一个回调函数
#         # 等待ret对应的任务有了结果之后立即调用print——func这个函数,立即对结果进行处理
#         # 而不是按照顺序接收结果处理结果
#         # future_l[i] = ret
#     # for key in future_l:
#     #     print(key, future_l[key].result())

队列机制实现回调机制(回调机制的实现原理)-异步阻塞


```python
import time
import random
import queue
from threading import Thread


def func(q, i):
    print('start', i)
    time.sleep(random.randint(1, 5))
    print('end', i)
    q.put(i * (i + 1))


def print_func(q):
    print(q.get())


q = queue.Queue()
for i in range(20):
    Thread(target=func, args=(q, i)).start()
for i in range(20):
    Thread(target=print_func, args=(q,)).start()

回调函数的例子

import requests
import os
from concurrent.futures import ThreadPoolExecutor


def get_page(url):  # 访问网页,获取网页源代码线程池中的线程来操作
    print('<进程%s> get%s' % (os.getppid(), url))
    response = requests.get(url)
    if response.status_code == 200:
        return {'url': url, 'text': response.text}


def parse_page(res):  # 获取到字典结果后,计算网页源码的长度,把https://www.baidu.com:192974729
    # 写到文件里,线程任务执行完毕之后绑定回调函数
    res = res.result()
    print('<进程%s> parse %s' % (os.getpid(), res['url']))
    parse_res = 'url:<%s> size:[%s]\n' % (res['url'], len(res['text']))
    with open('db.txt', 'a') as f:
        f.write(parse_res)


if __name__ == '__main__':
    urls = [
        'https://www.baidu.com',
        'https://www.python.org',
        'https://www.openstack.org',
    ]
    # 线程池开启
    tp = ThreadPoolExecutor(4)
    # 循环urls列表
    for url in urls:
        # 得到一个futures对象=把每一个url提交一个get_page任务
        ret = tp.submit(get_page, url)
        # 给feature对象绑定一个parse_page回调函数
        ret.add_done_callback(parse_page)
不用回调函数:
按照顺序获取网页,
也只能按顺序写
用了回调函数
按照顺序获取网页,哪一个网页先返回结果,就先执行那个网页对应的parserpage(回调函数)

要求
会起池,会提交任务
会获取返回值,会用回调函数


进程池(高计算的场景,没有io(没有文件操作\没有数据库操作\没有网络操作\没有input)):
>cpu_count*1 <cpu_count*2
线程池(一般根据io的比例定制):cpu_count*5        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值