多线程爬虫

多线程

一、线程是什么?
1、线程是进程中包含的执行单元
二、它有什么特点?
1、1个进程可包含多个线程
2、1次只能执行1个线程
3、线程锁(资源竞争问题)

二、主线程和子线程的执行关系
1、主线程会等待子线程结束之后在结束
2、join() 等待子线程结束之后,主线程继续执行
3、setDaemon() 守护线程,不会等待子线程结束

import time
import threading

def demo1():
    for i in range(5):
        print('hello everybody')
        time.sleep(1)


if __name__ == '__main__':
    t = threading.Thread(target=demo1)
    t.setDaemon(True) # 守护进程
    t.start()
    t.join() # 等待子线程执行结束之后我在执行
    print(1)

# 主线程会等待子线程结束之后在结束

创建多线程

一、通过函数创建多线程
使用threading模块当中的一个Thread类,有一个参数target参数,需要我们传递一个函数对象。一般这个函数是用来实现 线程的逻辑

import threading
import time

def fun():
    print('我是第%d个子线程'%i)

if __name__ == '__main__':
    for i in range(5):  # # 从0开始到4 一共5次 最后一个输出的是:我是第4个子线程
        t = threading.Thread(target=fun)
        time.sleep(1)
        t.start()

2、通过类
自定义一个类吗,需要继承父类 threading.Thread 并重新run()方法 实现线程的逻辑

class F(threading.Thread):

    def fun1(self):
        for i in range(1, 6):  # 从1开始到6 一共5次 最后一个输出的是:我是第5个子线程
            time.sleep(1)
            print('我是第%d个子线程' % i)

if __name__ == '__main__':
    a = F()
    a.fun1()

查看线程的数量

一、使用enumerate()

import threading
import time
threading.enumerate()

def demo1():
    for i in range(5):
        print('demo1--%d'%i)
        time.sleep(1)


def demo2():
    for i in range(10):
        print('demo2--%d' % i)
        time.sleep(1)


def main():
    t1 = threading.Thread(target=demo1,name='demo1')
    t2 = threading.Thread(target=demo2,name='demo2')
    t1.start()
    t2.start()
    while True:
        print(threading.enumerate()) # 查看线程数量
        if len(threading.enumerate()) <= 1:  # 当线程数小于等于1
            break
        time.sleep(1)
if __name__ == '__main__':
    main()

线程间的资源竞争

import threading
import time
# 线程的优点: 效率快  缺点: 线程比较多的时候会出现的问题 1、数据不完整 2、报BUG  json()数据 需要控制爬取的频率
# 创建一个线程锁 咋上锁?看源码
# lock = threading.Lock() # 不可重复的锁 只能上一次
lock = threading.RLock()  # 如果非要多次上锁就使用RLock() 方法
num = 0

def demo1(nums):
    global num
    # 上锁
    lock.acquire()
    lock.acquire()
    for i in range(nums): # 100 0 - 99  100
        num += 1
    # 解锁
    lock.release()
    lock.release()
    print('demo1-num-%d' % num)

def demo2(nums):
    global num
    lock.acquire()
    for i in range(nums):
        num += 1
    lock.release()
    print('demo2-num-%d' % num)

# 因为线程之间的资源竞争关系当数据大到一定程度时到的结果会出现错误所以这里我们需要使用线程锁来解决
def main():
    t1 = threading.Thread(target=demo1,args=(1000000,))  # 结果为demo1-num-1000000 正确
    t2 = threading.Thread(target=demo2,args=(1000000,))  # 结果为demo2-num-1650015 是错误的正确的应该是demo2-num-2000000
    t1.start()
    # time.sleep(3)
    # t1.join()
    t2.start()
    # t2.join()
    time.sleep(2)
    print('main-num-%d' % num)  # 结果为main-num-1477872是错误的正确结果应该是main-num-2000000


if __name__ == '__main__':
    main()

线程锁

# 线程锁
import threading
import time
# 线程的优点: 效率快  缺点: 线程比较多的时候会出现的问题 1、数据不完整 2、报BUG  json()数据 需要控制爬取的频率
# 创建一个线程锁 咋上锁?看源码
# lock = threading.Lock() # 不可重复的锁 只能上一次
lock = threading.RLock()  # 如果非要多次上锁就使用RLock() 方法
num = 0

def demo1(nums):
    global num
    # 上锁
    lock.acquire()
    lock.acquire()
    for i in range(nums): # 100 0 - 99  100
        num += 1
    # 解锁
    lock.release()
    lock.release()
    print('demo1-num-%d' % num)

线程队列Queue

一、队列的特点 先进先出
1、empty() 判断队列是否为空
2、full() 判断队列是否满了
3、get() 从队列当中取出数据
4、put() 将一个数据添加到队列当中

from queue import Queue

'''
爬虫
empty() 判断队列是否为空
full() 判断队列是否满了
get() 从队列当中取出数据
put() 将一个数据添加到队列当中

'''

a = Queue(3)
# empty() 判断队列是否为空 True代表是空的  False 代表队列不是空的
# print(a.empty())  # 结果为True
# 结果为True  l() 判断队列是否满了 False代表不是满的 True 代表队列满了
# print(a.full()) # 结果为False
# put() 将一个数据添加到队列当中
a.put(1)
a.put(2)
a.put(3)
# a.put(4)  # 如果超过线程列队 程序就会阻塞
# print('*'*80)
# print(a.empty())   # 结果为False
# print(a.full())  # 结果为 True  代表队列满了
# a.put(4,timeout=2)
# a.put_nowait(4)
# get() 从队列当中取出数据
# print(a.get())  # 结果为 1
# print(a.get())  # 结果为 2
# print(a.get())  # 结果为 3
# print(a.get())  # 超过线程就提取不出数据 并阻塞程序
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值