python中对多线程的理解

前言

在上个项目中,初步采集了知道的问题、问题url以及问题id,可是在采集的过程中我发现,爬取速度太慢,几乎每几秒才能得到一条数据,为了提升效率,我在想,能不能通过某个方式提高数据抓取的效率,最后考虑使用python中的多线程来实现。

多线程的介绍

什么是线程,进程?多进程,多线程又是什么?
如果将1台电脑比作1个工厂,里面的员工比作一个进程,那么
当这个厂只有1名员工在只做1件事的时候,那就是单进程单线程。
当这个厂有2名或者2名以上的员工在同时只做1件事的时候,那就是多进程
当这个厂只有1名员工在同时做不同事情的时候,那这个时候就是多线程。
注意:线程是基于进程而存在的,运行效率上单线程速度最慢,多线程和多进程的速度相似,但是多进程所占用的资源最多,一般使用多线程或者协程

多进程的使用

直接导入threading模块

import threading

threading模块中最核心的内容是Thread这个类

通常来说,我们想要创建多少个线程,就是创建多少个Thread对象,Thread对象的数量就是线程的数量,同时我们还能指定每一个线程中所做不同的事情,这就是多线程编程,同时多线程之间使用队列Queue来进行通信。

创建Thread对象有两种方法:

  1. 直接创建Thread,将运行函数传入,使用start()方法开启线程处理任务。
  2. 编写一个自定义类继承Thread,复写Thread中的run()方法,将需要处理的任务写入,最后创建Thread的子类,通过start()开启线程

总的来说,两种方法都能创建Thread对象,不过第二种方法符合面向对象思想,一般使用第二种。

Thread两种创建对象的方法与demo

1、直接创建Thread,将函数传入其中,调用start()方法开启线程

import threading
import time

def test1():
    print("test1 start_time:\t",time.time())
    time.sleep(5)
    print("test1 over_time:\t",time.time())

def test2():
    print("test2 start_time:\t",time.time())
    time.sleep(2)
    print("="*40)
    print("test2 over_time:\t",time.time())

if __name__ == "__main__":
	# 创建对象,这里传入的是函数,不需要执行,因此不用在函数后加括号
    test_1 = threading.Thread(target=test1)
    test_2 = threading.Thread(target=test2)
    # 开启线程
    test_1.start()
    test_2.start()
    # 等待线程
    test_1.join()
    test_2.join()

运行结果:
多线程运行结果
从运行结果可以看出,程序几乎是同时执行的两个函数,由于两个函数sleep的时间不同,所以结束的时间也不相同。

2、编写一个自定义类继承Thread,复写Thread中的run()方法,将需要处理的任务写入,最后创建Thread的子类,通过start()开启线程
我们先来看例子,下面是自定义类继承Thread实现多线程的demo:

import threading
import time

class test(threading.Thread):
    def __init__(self, name):
        super(test, self).__init__()
        self.name = name

    def run(self):
        print("{0}\tstart_time:\t{1}".format(self.name, time.time()))
        time.sleep(3)
        print("\n{0}\tover_time:\t{1}".format(self.name, time.time()))

def main():
    test_list_name = []
    test_list = []
    # 批量生成线程名字,存入列表
    for i in range(1, 4):
        name = str(i) + "号test"
        test_list_name.append(name)
    # 根据名字列表的数量创建线程,并开启
    for threadName in test_list_name:
        thread = test(threadName)
        thread.start()
        test_list.append(thread)
    # 等待所有线程结束
    for i in test_list:
        i.join()
        
if __name__ == "__main__":
    main()

下面是运行结果图:
多线程02
自此,我们可以使用多线程来同时处理不同的任务。

Queue(队列)

有时候在某些项目中要使用多线程实现生产者-消费者模式,所以就要解决线程之间的通信问题,这就要用到queue(队列)来解决线程之间的通信问题。

  • Queue.qsize() ---- 返回当前队列包含消息数量
  • Queue.empty() ---- 如果队列为空,返回True,反之则为False
  • Queue.full() ---- 当队列满时返回True;当队列为空时返回False
  • Queue.get() ---- 从队列中提取一条信息,若无信息则弹出异常(异常类型:Queue.Empty)
  • Queue.put() ---- 将一条数据存入队列中

注:
1、Queue 是 先进先出 类型
2、多线程共享全局变量
3、但是多线程同时操作一个全局变量的时候会有bug,可以选择轮询或者使用互斥锁解决。

附:

在做完第一个项目不久,考虑是不是可以用多线程的方式去实现,随着我对多线程进一步的理解,就开始着手对我第一个项目进行重构。?

  • 加入了IP池(感谢GitHub大神的IPProxy项目)
  • 加入多线程进行爬取、解析
  • 将获取的数据存入mysql
  • 使用互斥锁、添加延时等方式降低程序死锁风险

具体代码可以到我的GitHub查看------>点这里

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值