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

     

                                            

          点个好看啊~~(破音)

  • 相关阅读:
    音视频之PCM转WAV(八)
    音视频之播放YUV数据(十二)
    音视频之视频录制(十)
    报错error: missing D__STDC_CONSTANT_MACROS / #define __STDC_CONSTANT_MACROS
    Vue组件广告滚动
    配置Vue中@符,出现路径提示
    iOS WKWebView后台崩溃问题排查
    vue element 静态分页
    vue Vue __ob__: Observer 取值
    csdn 复制代码
  • 原文地址:https://www.cnblogs.com/fxxkpython/p/10832210.html
Copyright © 2011-2022 走看看