Python爬虫之线程池

详情点我跳转

关注公众号“轻松学编程”了解更多。

一、为什么要使用线程池?

对于任务数量不断增加的程序,每有一个任务就生成一个线程,最终会导致线程数量的失控,例如,整站爬虫,假设初始只有一个链接a,那么,这个时候只启动一个线程,运行之后,得到这个链接对应页面上的b,c,d,,,等等新的链接,作为新任务,这个时候,就要为这些新的链接生成新的线程,线程数量暴涨。在之后的运行中,线程数量还会不停的增加,完全无法控制。所以,对于任务数量不端增加的程序**,固定线程数量的线程池是必要的**。

二、如何实现线程池?

1、使用threadpool

使用threadpool模块,这是个python的第三方模块

pip install threadpool

示例:

import threadpool
import time

# 任务
def doSth(args):
    print("hello", args)

# 回调
def call_back(a, b):
    print(a, b)
    print("线程执行完毕")

if __name__ == '__main__':
    time.clock()
    #创建线程池,线程并发数量为5
    pool = threadpool.ThreadPool(5)
    #创建线程,要执行得到任务数量为6,即创建6个线程
    argsList = [1,2,3,4,5,6]
    requests = threadpool.makeRequests(doSth,argsList,callback=call_back)
    '''
    makeRequests(callable_, args_list, callback=None,exc_callback=_handle_thread_exception)
        其中的参数:
        callable_, 线程要执行的方法
        args_list, 列表,实参
        callback=None,线程执行完回调的函数
        exc_callback=_handle_thread_exception 异常处理
        '''
    # print(requests)

    for req in requests:
        # 执行
        pool.putRequest(req)
    # 保证线程池里面的线程结束
    pool.wait()
    # 输出程序运行花费的时间
    print(time.clock())

threadpool是一个比较老的模块了,已经不再是主流了,关于python多线程,现在已经开始步入未来(future模块)了 。

2、使用concurrent.futures模块

这个模块是python3中自带的模块 。

from concurrent.futures import ThreadPoolExecutor

# 任务
def doSth(args):
    print("hello", args)

if __name__ == '__main__':
    # max_workers 线程数
    argsList = (1, 2, 3, 4, 5,6)
    # 使用sumbit()函数提交任务
    with ThreadPoolExecutor(5) as exe:
        for a in argsList:
            # fn,
            # *args 不定长位置参数
            #  **kwargs 不定长关键字参数
            exe.submit(doSth,a)
    # 使用map()函数提交任务
    print("使用map()提交任务")
    with ThreadPoolExecutor(5) as exe:
        #  fn, 方法
        # *iterables 可迭代对象 ,如、列表
        exe.map(doSth, argsList)

注意:map可以保证输出的顺序, submit输出的顺序是乱的

如果你要提交的任务的函数是一样的,就可以简化成map。但是假如提交的任务函数是不一样的,或者执行的过程之可能出现异常(使用map执行过程中发现问题会直接抛出错误)就要用到submit()

submit和map的参数是不同的,submit每次都需要提交一个目标函数和对应的参数,map只需要提交一次目标函数,目标函数的参数放在一个迭代器(列表,字典)里就可以。

三、分配线程数

把多个爬取任务分配到线程列表中

# 任务数
tasks = [i for i in range(103)]
#线程列表
threadLit = [[] for _ in range(5)]

#把任务均等分配到程序列表中
for i in range(len(tasks)):
    threadLit[i % 5].append(tasks[i])

for i in threadLit:
    print(i)

输出:

[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100]
[1, 6, 11, 16, 21, 26, 31, 36, 41, 46, 51, 56, 61, 66, 71, 76, 81, 86, 91, 96, 101]
[2, 7, 12, 17, 22, 27, 32, 37, 42, 47, 52, 57, 62, 67, 72, 77, 82, 87, 92, 97, 102]
[3, 8, 13, 18, 23, 28, 33, 38, 43, 48, 53, 58, 63, 68, 73, 78, 83, 88, 93, 98]
[4, 9, 14, 19, 24, 29, 34, 39, 44, 49, 54, 59, 64, 69, 74, 79, 84, 89, 94, 99]

后记

【后记】为了让大家能够轻松学编程,我创建了一个公众号【轻松学编程】,里面有让你快速学会编程的文章,当然也有一些干货提高你的编程水平,也有一些编程项目适合做一些课程设计等课题。

也可加我微信【1257309054】,拉你进群,大家一起交流学习。
如果文章对您有帮助,请我喝杯咖啡吧!

公众号

公众号

赞赏码

关注我,我们一起成长~~

posted @ 2018-07-09 19:05  轻松学编程  阅读(145)  评论(0编辑  收藏  举报