python3爬虫学习之多线程初入

在这里首先上两段代码了解一下使用多线程和不使用多线程的区别,从而了解多线程的用处

一,

1,不使用多线程

import time

#未使用多线程,运行该程序需大概6秒
def speaking_demo():
    for x in range(3):
        print("我在说话 %s" % x)
        time.sleep(1)#停止一秒

def writing_demo():
    for x in range(3):
        print("我在写字 %s" % x)
        time.sleep(1)#停止一秒

def main():
    speaking_demo()
    writing_demo()

if __name__ == '__main__':
    main()

这是一个非常普通的代码段,轮流执行speaking和writing,每次执行完都沉睡一秒,执行时间极短,我们忽略,运行完整个代码段大概6秒

2,使用多线程

import threading
import time

#使用线程,两个函数会几乎同时运行,时间约3秒
def speaking_demo():
    for x in range(3):
        print("我在说话 %s" % x)
        time.sleep(1)#停止一秒

def writing_demo():
    for x in range(3):
        print("我在写字 %s" % x)
        time.sleep(1)#停止一秒

def main():
    t_1 = threading.Thread(target=speaking_demo) #创建线程1,传值时传入函数名,不加括号
    t_2 = threading.Thread(target=writing_demo) #创建线程2,

    t_1.start()#开始线程1
    t_2.start()#开始线程2

if __name__ == '__main__':
    main()

我们使用了多线程来执行这两个函数,当进程把执行speaking任务给到线程1的时候,它不会等线程1执行完再去把writing任务给线程2执行,而是几乎在把speaking任务给线程1的同时,把writing任务给线程2,所以speaking和writing任务几乎是同时执行,所以,运行这个代码段大概需要3秒。

那么,上面的写法是不规范的,我们了解一下规范的写法,让它继承自父类

import threading
import time

class Speaking_demo(threading.Thread):
    def run(self):#重写run方法
        for x in range(3):
            print("我在说话 %s " % threading.current_thread())#该方法查看线程名
            time.sleep(1)

class Writing_demo(threading.Thread):
    def run(self):
        for x in range(3):
            print("我在写字 %s " % threading.current_thread())
            time.sleep(1)

def main():
    t1 = Speaking_demo()
    t2 = Writing_demo()

    t1.start()
    t2.start()
    print(threading.enumerate())#该方法查看线程数

if __name__ == '__main__':
    main()

那么,在代码中,也注释了几种常用方法。不在一一赘述。

二,我们来了解一下全局问题与锁机制

首先,我们看一个例子,在这个例子中,我们不使用锁

import threading

value = 0

#创建test方法,该方法使全局变量+1 ,当值足够大时,未使用锁机制,线程会混乱导致程序出错
def test():
    global value #调用全局变量
    for x in range(100):
        value += 1
    print(value)

def main():
    for x in range(2):
        t1 = threading.Thread(target=test)
        t2 = threading.Thread(target=test)

    t1.start()
    t2.start()
#
if __name__ == '__main__':
    main()

我们给了一个test方法,使全局变量+1,当我们循环100次,并使用两个线程时,第一个线程会把它加到100,第二个会把它加到200,我们看看结果

我们再试试更大的数,1000000

明显结果是错的。

我们使用锁机制在试试

import threading

value = 0

gLock = threading.Lock()
def test():
    global value #调用全局变量
    gLock.acquire()#加锁
    for x in range(1000000):
        value += 1
    gLock.release()#释放锁
    print(value)

# #创建main方法,用test方法建立两个线程
def main():
    for x in range(2):
        t1 = threading.Thread(target=test)
        t2 = threading.Thread(target=test)

    t1.start()
    t2.start()
#
if __name__ == '__main__':
    main()

我们得到了正确的结果,锁机制,会在一个线程调用并需要改变全局变量时,阻止其他线程调用改变该全局变量,避免引起混乱,加锁之后一定要释放锁。

另外,如果我们只是调用查看全局变量,则不需要锁机制,在改变全局变量时,一定要加锁。

三:我们简单了解一下安全队列:

from queue import Queue

q = Queue(4) #定义一个安全队列,容量4

for x in range(4):
    q.put(x) #put方法把元素放入队列

print(q.full())#full 方法判断队列是否满

for x in range(4):
    q.get() #get方法获取队列值,并将该值从队列中移除

print(q.empty()) #empty 方法判断队列是否空

上面给了安全队列的几种常用方法。

后续我们实战会用到。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值