python多进程与多线程(三):多线程与多线程爬虫简介

前言

Python的标准库提供了两个模块:_thread和threading,_thread是低级模块,threading是高级模块,对_thread进行了封装。绝大多数情况下,我们只需要使用threading这个高级模块。
启动一个线程就是把一个函数传入并创建Thread实例,然后调用start()开始执行。
虽然python的多线程受GIL限制,并不是真正的多线程,但是对于I/O密集型计算还是能明显提高效率,比如说爬虫。详细请见 https://www.zhihu.com/question/23474039

创建的两种方式

面向过程(常用)

import time, threading

# 假定这是你的银行存款:
balance = 0

def change_it(n):
    # 先存后取,结果应该为0:
    global balance
    balance = balance + n
    balance = balance - n

def run_thread(n):
    for i in range(100000):
        change_it(n)

t1 = threading.Thread(target=run_thread, args=(5,))  # args是你调用函数的参数哦
t2 = threading.Thread(target=run_thread, args=(8,))
t1.start()
t2.start()

print(balance)

面向对象

手写一个子类,继承父类Thread,重写run方法

# -*-coding:utf-8 -*-
import threading

class MyThread(threading.Thread):
    def __init__(self, func, args):
        threading.Thread.__init__(self)  # 调用父类的构造函数
        self.args = args
        self.func = func
    def run(self):  # 线程活动方法
        self.func(self.args[0])  # 启动这个函数args是元组,取出指定元素

def count(n):
    for i in range(n):
        print(n)

t1 = MyThread(count,(10,))
t1.start()
t1.join()

join与start的区别

start() 方法是启动一个子线程,线程名就是我们定义的name

run() 方法并不启动一个新线程,就是在线程中调用了一个普通函数而已。

详情参照点击跳转

脏数据与互斥锁

多线程稍不注意就会把数据弄脏,为了避免这种状况,我们需要使用线程锁。
如下:

import threading

# 假定这是你的银行存款:
balance = 0

def change_it(n):
    # 先存后取,结果应该为0:
    global balance
    balance = balance + n
    balance = balance - n

def run_thread(n):
    for i in range(2000000):
        change_it(n)

t1 = threading.Thread(target=run_thread, args=(5,))
t2 = threading.Thread(target=run_thread, args=(8,))
t1.start()
t2.start()
t1.join()
t2.join()
print(balance)

我们先加后减,按理说最后应该输出0,但是其不是。(你可以跑一下试试)
究其原因,是因为修改balance需要多条语句,而执行这几条语句时,线程可能中断,从而导致多个线程把同一个对象的内容改乱了。
如果我们要确保balance计算正确,就要给change_it()上一把锁,当某个线程开始执行change_it()时,我们说,该线程因为获得了锁,因此其他线程不能同时执行change_it(),只能等待,直到锁被释放后,获得该锁以后才能改。由于锁只有一个,无论多少线程,同一时刻最多只有一个线程持有该锁,所以,不会造成修改的冲突。创建一个锁就是通过threading.Lock()来实现:

balance = 0
lock = threading.Lock()

def run_thread(n):
    for i in range(100000):
        # 先要获取锁:
        lock.acquire()
        try:
            # 放心地改吧:
            change_it(n)
        finally:
            # 改完了一定要释放锁:
            lock.release()

爬虫与多线程

本人详细说明了爬虫中如何使用多线程,以及相关模板。点击跳转

参考教程

廖雪峰: 点击跳转

菜鸟教程: 点击跳转

脚本之家:点击跳转

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笼中小夜莺

嘿嘿嘿,请用金钱尽情地蹂躏我吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值