进程和线程池

进程池

为什么会有进程池的概念:

进程过多,操作系统的调度会很耗时,效率低。

进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池内没有可供使用的进程,那么程序就会等待,直到进程池中有可用的进程为止。

进程池和信号量的区别:
进程池是先创建5个进程,然后200个任务排队,同时只有5个任务执行。
信号量是先创建200个进程,同时有5个进程执行。

进程池相对于信号量的优点:
1、节省了195个进程的创建时间
2、节省了195个进程的内存占用
3、节省了操作系统对195个进程的调度时间

更高级的进程池
进程池的大小在n到m之间。适用于高峰期和低峰期。
优点:高峰期增加并发量。低峰期回收不用的进程。

from multiprocessing import Process, Pool
import time


def func(n):
    print('start %s' %(n))
    time.sleep(1)
    print('end %s' %(n))


if __name__ =='__main__':
    pool = Pool(5)
    for i in range(10):
        pool.apply_async(func, args=(i,))
    pool.close()
    pool.join()

进程池的返回值

一、p.map(funcname, iterable) 默认异步的执行任务,且自带close和join
(1)返回值是所有进程的结果放到一个列表里
二、p.apply() 同步调用的,很少用
(1)只有func执行完之后,才会继续向下执行其他代码
(2)返回值就是func的返回值
三、p.apply_async() 异步调用,和主进程完全异步,需要手动close和join
(1) 异步的:当func被注册进入一个进程之后,程序就继续向下执行
(2) -返回值:返回一个对象,可以从对象里获取func函数的返回值obj.get,get会阻塞直到对应的func执行完毕拿到结果
(3) -使用apply_async给进程池分配任务
(4) -需要先close后join来保持多进程和主进程代码的同步性

1、apply_async异步

from multiprocessing import Pool
import time


def func(i):
    time.sleep(1)
    return i*i


if __name__ == '__main__':
    p = Pool(5)
    res_l = []
    for i in range(10):
        res = p.apply_async(func, args=(i,))   # apply_async的返回值就是函数func的返回值
        res_l.append(res)

    for res in res_l:
        print(res.get())      # 等着func的计算结果,会进行阻塞

2、 map异步

from multiprocessing import Pool
import time


def func(i):
    time.sleep(1)
    return i*i


if __name__ == '__main__':
    p = Pool(5)
    res = p.map(func, range(10))    # map异步执行任务,自带close和join方法
    print(res)     # 所有任务都完成之后,返回一个所有结果的列表

进程池的回调函数
(1)回调函数是在主进程中执行
(2)子进程函数的返回值是回调函数的参数
(3)回调函数在爬虫的时候用的多,因为从网上下载延时最高的。用回调函数会节省下进程池的资源,用于下载。
(4)适用于回调函数执行任务的时间远远小于原函数执行的时间。

from multiprocessing import Pool
import os


def func1(n):
    print('in func1', os.getpid())
    return n*n


def func2(nn):
    print('in func2', os.getpid())   # 回调函数在主进程里执行
    print(nn)


if __name__ == '__main__':
    print('主进程', os.getpid())
    p = Pool(5)
    for i in range(10):
        p.apply_async(func1, args=(10,), callback=func2)  # 回调函数的参数是func1函数的返回值
    p.close()
    p.join()

数据爬取中使用回调函数

import requests
from multiprocessing import Pool


def get(url):
    response = requests.get(url)
    if response.status_code == 200:
        return url, response.content.decode('utf-8')


def call_back(args):
    url, content = args
    print(url, len(content))


if __name__ == '__main__':
    url_l = [
        'https://www.cnblogs.com/',
        'http://www.baidu.com',
        'http://www.sohu.com',
        'https://www.sogou.com',
    ]
    p = Pool(5)
    for url in url_l:
        p.apply_async(get, args=(url,), callback=call_back)
    p.close()
    p.join()

线程中的条件锁

acquire() release()
一个条件被创建之初,默认有一个FALSE状态
wait() #等待notify发放钥匙,发放几个,就走几个线程,钥匙不归还。在acquire和release之间
FALSE状态,会影wait一直处于等待状态
notify(int数据类型) 制作钥匙

线程池

from concurrent.futures import ThreadPoolExecutor
import time


def func(n):
    time.sleep(1)
    print(n)
    return n*n


tpool = ThreadPoolExecutor(max_workers=5)
# tpool.map(func, range(20))   # 拿不到返回值
t_lst = []
for i in range(20):
    t = tpool.submit(func, i)
    t_lst.append(t)
tpool.shutdown()    # close和join的作用  close关闭线程池(不让别的任务进来) join线程池里面的线程执行完,加上这个效率低
print('主线程')
for t in t_lst:
    print(t.result())

线程池中的回调函数

from concurrent.futures import ThreadPoolExecutor
import time


def func(n):
    time.sleep(1)
    print(n)
    return n*n


def call_back(m):
    print('结果是%s' % m.result())


tpool = ThreadPoolExecutor(max_workers=5)
# tpool.map(func, range(20))   # 拿不到返回值
t_lst = []
for i in range(20):
    t = tpool.submit(func, i).add_done_callback(call_back)
    t_lst.append(t)
# tpool.shutdown()    # close和join的作用  close关闭线程池(不让别的任务进来) join线程池里面的线程执行完,加上这个效率低
print('主线程')
# for t in t_lst:
#     print(t.result())
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值