zoukankan      html  css  js  c++  java
  • python爬虫14 | 就这么说吧,如果你不懂python多线程和线程池,那就去河边摸鱼!

    你知道吗?

     

    在我的心里

     

    你是多么的重要

     

    就像

     

     

    请允许我来一段 freestyle

     

    你们准备好了妹油

     

    你看

     

    这个碗

     

     

    它又大又圆

     

    就像

     

    这条面

     

     

    它又长又宽

     

    你们

     

    在这里

     

    看文章

     

    觉得 很开心

     

    就像 

     

    我在这里

     

    给你们

     

    写文章

     

    觉得很开心

     

    skr~~

     

     

     

    不好意思

     

    走错片场了

     

    ok..

     

    接下来,就是

     

    学习 python 的正确姿势

     

     

     

    咱们在上一次的

     

    python爬虫13 | 秒爬,这多线程爬取速度也太猛了,这次就是要让你的爬虫效率杠杠的

     

    了解了一些 python 高效爬虫的概念

     

    比如多线程、多进程、协程等

     

    那么我们这一篇就开始了解多线程的具体使用

     

    在 python 中

     

    常用的多线程的模块有这么几个

     

    _thread

    threading

    Queue

     

    之前有个 thread 模块

     

    被 python3 抛弃了

     

    改名为  _thread

     

    但其实 _thread 也没什么人用

     

    因为 _thread 有的 threading 都有

     

    _thread 没有的 threading 依然有

     

     

    那么接下来我们就先来玩玩 threading 

     

    在此之前

     

    (请允许小帅b又开始吹水了~)

     

    介绍一下 小帅b 的一点背景

     

    小帅b呢

     

    平常上班时间都会去河边摸鱼

     

    每天得摸 20 条鱼

     

     

    一条一条的摸

     

    为的是什么

     

    为的是安抚这些鱼的心情

     

    这样以后送到餐前的红烧鱼才更加美味

     

     

     

     

    小帅b每天得摸 20 条鱼

     

    每隔一秒钟摸一条

     

    也就是这样

     

    import time

    def moyu_time(name, delay, counter):
     while counter:
       time.sleep(delay)
       print("%s 开始摸鱼 %s" % (name, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))
       counter -= 1


    if __name__ == '__main__':
     moyu_time('小帅b',1,20)

     

     

    后来

     

    小帅b知道了多线程

     

    拍脑一想

     

    我靠

     

    应该把小明和小红拉过来

     

    让他们一起帮我摸鱼啊

     

    也就是让小明和小红同时一人摸 10 条鱼

     

    想想就开心

     

     

    在 小帅b 的威逼利诱下

     

    他们俩不情愿的手拉着手来到了河边

     

    小帅b看小红是女生

     

    就让小红每摸一条鱼休息 2 秒钟

     

    而小明每摸一条鱼休息 1 秒钟

     

    先扔一段代码给你

     

    # encoding = utf-8

    import threading
    import time


    # 创建一个线程子类
    class MyThread(threading.Thread):
      def __init__(self,threadID, name, counter):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.counter = counter

      def run(self):
        print("开始线程:" + self.name)
        moyu_time(self.name, self.counter, 10)
        print("退出线程:" + self.name)

    def moyu_time(threadName, delay, counter):
      while counter:
        time.sleep(delay)
        print("%s 开始摸鱼 %s" % (threadName, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))
        counter -= 1


    # 创建新线程
    # 小帅b找了两个人来摸鱼
    # 让小明摸一次鱼休息1秒钟
    # 让小红摸一次鱼休息2秒钟
    thread1 = MyThread(1"小明"1)
    thread2 = MyThread(2"小红"2)

    # 开启新线程
    thread1.start()
    thread2.start()
    # 等待至线程中止
    thread1.join()
    thread2.join()
    print ("退出主线程")

     

    在这里呢

     

    我们创建了一个线程类

     

    然后继承 threading.Thread

     

    在我们这个线程类里面定义了一个 run 方法

     

    这个 run 方法去调用了摸鱼的方法

     

    可以看到我们创建了两个线程

     

    一个叫小明线程

     

    一个叫小红线程

     

    thread1 = MyThread(1"小明"1)
    thread2 = MyThread(2"小红"2)

     

     

    当我们的线程调用 start 方法的时候

     

    它们就会去执行 run 方法

     

    而我们用到的 join 方法呢

     

    是为了让线程执行完

     

    再终止主程序

     

     

    运行一下就是这样

     

    开始线程:小明
    开始线程:小红
    小明 开始摸鱼 2019-03-10 23:15:26
    小红 开始摸鱼 2019-03-10 23:15:27
    小明 开始摸鱼 2019-03-10 23:15:27
    小明 开始摸鱼 2019-03-10 23:15:28
    小红 开始摸鱼 2019-03-10 23:15:29
    小明 开始摸鱼 2019-03-10 23:15:29
    小明 开始摸鱼 2019-03-10 23:15:30
    小明 开始摸鱼 2019-03-10 23:15:31
    小红 开始摸鱼 2019-03-10 23:15:31
    小明 开始摸鱼 2019-03-10 23:15:32
    小明 开始摸鱼 2019-03-10 23:15:33
    小红 开始摸鱼 2019-03-10 23:15:33
    小明 开始摸鱼 2019-03-10 23:15:34
    小红 开始摸鱼 2019-03-10 23:15:35
    小明 开始摸鱼 2019-03-10 23:15:35
    退出线程:小明
    小红 开始摸鱼 2019-03-10 23:15:37
    小红 开始摸鱼 2019-03-10 23:15:39
    小红 开始摸鱼 2019-03-10 23:15:41
    小红 开始摸鱼 2019-03-10 23:15:43
    小红 开始摸鱼 2019-03-10 23:15:45
    退出线程:小红
    退出主线程

    Process finished with exit code 0

     

     

    小帅b再也不用摸鱼了

     

    后来小明和小红都不乐意了

     

    凭什么就我们两个摸鱼

     

     

    这时候 小帅b 只能去找更多人了

     

    连 小帅b 家的狗都叫过来了

     

    然后

     

    就疯狂的开启线程

     

    thread1 = MyThread(1"小明"1)
    thread2 = MyThread(2"小红"2)
    thread3 = MyThread(3"小黄"2)
    thread4 = MyThread(4"小绿"2)
    ...
    thread5 = MyThread(55"小青"2)
    thread6 = MyThread(56"小白"2)
    thread7 = MyThread(57"小狗"2)

     

     

    stop!!!

     

     

    这可不行

     

    因为频繁的创建线程 销毁线程

     

    非常的浪费资源

     

    所以呢

     

    应该把他们放到池子里面去一起洗澡

     

     

    哈,也就是

     

    线程池

     

    通过线程池就可以重复利用线程

     

    不会造成过多的浪费

     

    在 python 中

     

    可以使用 ThreadPoolExecutor 来实现线程池

     

    我们来往池子里塞 20 个线程

     

    然后在循环的时候每次拿一个线程来摸鱼

     

    def moyu_time(name, delay, counter):
      while counter:
        time.sleep(delay)
        print("%s 开始摸鱼 %s" % (name, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))
        counter -= 1


    if __name__ == '__main__':
      pool = ThreadPoolExecutor(20)
      for i in range(1,5):
        pool.submit(moyu_time('xiaoshuaib'+str(i),1,3))

     

    运行一下

     

    xiaoshuaib1 开始摸鱼 2019-03-10 23:30:10
    xiaoshuaib1 开始摸鱼 2019-03-10 23:30:11
    xiaoshuaib1 开始摸鱼 2019-03-10 23:30:12
    xiaoshuaib2 开始摸鱼 2019-03-10 23:30:13
    xiaoshuaib2 开始摸鱼 2019-03-10 23:30:14
    xiaoshuaib2 开始摸鱼 2019-03-10 23:30:15
    xiaoshuaib3 开始摸鱼 2019-03-10 23:30:16
    xiaoshuaib3 开始摸鱼 2019-03-10 23:30:17
    xiaoshuaib3 开始摸鱼 2019-03-10 23:30:18
    xiaoshuaib4 开始摸鱼 2019-03-10 23:30:19
    xiaoshuaib4 开始摸鱼 2019-03-10 23:30:20
    xiaoshuaib4 开始摸鱼 2019-03-10 23:30:21

     

     

    可以看到

     

    我们每次从线程池里面去拿一个线程来摸鱼

     

    这样就不会去重复的创建销毁线程了

     

    当然

     

    我们还可以用一个叫做 Queue 的队列来创建线程池

     

    队列嘛~

     

    就是可以往里塞东西

     

    也可以往里拉东西

     

    所以我们在使用队列的时候

     

    最常用的方法就是 put 和 get 了

     

    还是拿摸鱼为例

     

    我们创建一个长度为 6 的队列

     

    接着根据队列的长度创建了线程

     

    每个线程都让它们处于守护状态

     

    也就是需要的时候

     

    马上执行

     

    def queue_pool():
      queue = Queue(6)
      for i in range(queue.maxsize):
        t = CustomThread(queue)
        t.setDaemon(True)
        t.start()

     

    接着我们就可以用 put 方法

     

    把我们想做的事情往队列里面塞

     

    比如这里我们想要摸鱼

     

    for i in range(20):
      queue.put(moyu)
    queue.join()

     

     

    def moyu():
      print(" 开始摸鱼 %s" % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))

     

    要执行的话就需要去队列里面取了

     

    q_method = self.__queue.get()
    q_method()
    self.__queue.task_done()

     

    完整代码如下

     

    import threadingimport timefrom queue import Queue

    class CustomThread(threading.Thread): def __init__(self, queue): threading.Thread.__init__(self) self.__queue = queue
    def run(self): while True: q_method = self.__queue.get() q_method() self.__queue.task_done()
    def moyu(): print(" 开始摸鱼 %s" % (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())))
    def queue_pool(): queue = Queue(5) for i in range(queue.maxsize): t = CustomThread(queue) t.setDaemon(True) t.start()
    for i in range(20): queue.put(moyu) queue.join()
    if __name__ == '__main__': queue_pool()

     

    本篇就到这里吧

     

    ps:本来想接着写一下用多线程来爬取网站的,篇幅有限,咱们下一篇再见

     

    peace

     

                                            

          点个好看啊~~(破音)

  • 相关阅读:
    TextBox 只有下划线
    can't find web control library(web控件库)
    DropDownListSalesAC”有一个无效 SelectedValue,因为它不在项目列表中。
    IDE、SATA、SCSI、SAS、FC、SSD 硬盘类型
    如何打印1px表格
    CSS控制打印 分页
    Virtual Server could not open its emulated Ethernet switch driver. To fix this problem, reenable the Virtual Server Emulated Et
    Xml中SelectSingleNode方法中的xpath用法
    热带水果莫入冰箱?水果存放冰箱大法
    探索Asp.net的Postback机制
  • 原文地址:https://www.cnblogs.com/fxxkpython/p/10832210.html
Copyright © 2011-2022 走看看