首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >多线程的使用

多线程的使用

作者头像
爱撒谎的男孩
发布2018-05-25 16:05:43
5410
发布2018-05-25 16:05:43
举报
文章被收录于专栏:码猿技术专栏码猿技术专栏

多线程

前言

我看了不止一个人说多线程是鸡肋,但是就依照我个人觉得多线程在一些小型的爬虫中还是可以显著的提高速度的,相比多进程来说应该还是挺简单的

使用多线程

继承threading.Thread

继承threading.Thread模块是一个很好的一个选择,就像java中也是可以继承类和实现接口一样,这都是很好的选择,下面我们来看看具体如何使用

1234567891011121314151617181920212223242526

class Mythread(threading.Thread): def __init__(self,threadID,name,counter): threading.Thread.__init__(self) #首先需要先保留原来threading.Thread中的初始化函数 self.threadID=threadID #重命名线程的ID self.name=name #线程的名字 self.counter=counter #线程的数量 def run(self): lock.acquire() #获取线程锁Lock for i in range(10): print "线程"+self.name+"开始运行" lock.release() #释放线程锁Lockif __name__ == '__main__': lock=threading.Lock() t1=Mythread(0,"thread-1",3) t2=Mythread(1,"thread-2",3) t1.start() t2.start() threads=[] threads.append(t1) threads.append(t2) for t in threads: t.join() #阻塞主线程,直至线程运行完毕才运行main线程的语句 print "线程运行结束"

需要注意的是,这种继承的方式有一个缺点,这个和java中继承来实现多线程是一样的,就是一个对象只能是对应一个线程,并不能一个对象被多个线程共享,下面我们将会介绍另外的一种方式

直接调用threading.Thread

上面我们说过继承的方式,但是我个人觉得对于一些比较小的爬虫还是有些繁琐的,因为总是需要重写run方法,现在我们来看看如何简化实现多线程

12345678910

"""这是一个简单的例子,其实也不是一个好的例子,但是为了演示方便就选用了,可以看出这里是直接调用了func函数,然后变成多个线程同时并行,其中target是要调用的方法(没有括号),args是方法调用需要传入的参数其实这个还是和上面的继承比较相似的"""def func(name,age): for i in range(10): print name+"的年龄为:"+str(age) t=threading.Thread(target=func,args=["陈加兵",22])t.start()

Thread对象的相关方法

  • start() 启动线程
  • join([timeout]) 设置阻塞线程,timeout是可选的参数,表示阻塞的时间,如果没有就是当此线程运行结束才开始运行下一个线程
  • run() 线程活动的方法
  • getName() 获取线程名称
  • setName() 设置线程的名称
  • isAlive() 判断线程是否还活着
  • isDaemon() 判断是否是守护线程
  • setDaemon() 设置为守护线程,守护线程就是当主线程运行完后,这个线程也会随着主线程的结束而结束

共享队列

从源代码可以看出队列是实现了锁原语的,因此可以使用队列实现线程的同步,这里的主要原理就不细说了,简单的说就是get和put等方法都实现了锁原语,就是当一个操作正在执行的时候其他的操作会阻塞等待 下面我自己写了一个使用两个线程实现同时入队和出队的程序

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556

import randomimport timefrom Queue import Queueclass myThread(threading.Thread): def __init__(self,threadID,name,counter,q,flag): """ threadID是线程的ID name是线程的名称 q是先进先出队列 flag是用来调用get和put的标志 """ threading.Thread.__init__(self) self.name=name self.threadID=threadID self.counter=counter self.q=q self.flag=flag def run(self): """ 当flag为1时就调用put方法,否则调用get """ if self.flag==1: self.put() else: self.get() def put(self): while True: self.q.put(random.randint(0,10)) def get(self): while True: if not self.q.empty(): print self.q.get() if __name__=="__main__": threadLock=threading.Lock() q=Queue() t1=myThread(1,"Thread-1",1,q,1) t2=myThread(2,"Thread-2",2,q,2) threads=[] threads.append(t1) threads.append(t2) t1.start() t2.start()

Queue相关的一些方法

  1. Queue.qsize() 返回队列的大小
  2. Queue.empty() 如果队列为空,返回True,反之False
  3. Queue.full() 如果队列满了,返回True,反之False
  4. Queue.full 与 maxsize 大小对应
  5. Queue.get([block[, timeout]])获取队列,timeout等待时间
  6. Queue.get_nowait() 相当Queue.get(False)
  7. Queue.put(item) 写入队列,timeout等待时间
  8. Queue.put_nowait(item) 相当Queue.put(item, False)
  9. Queue.task_done() 在完成一项工作之后, Queue.task_done()函数向任务已经完成的队列发送一个信号
  10. Queue.join() 实际上意味着等到队列为空,再执行别的操作
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-09-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 多线程
    • 前言
      • 使用多线程
        • 继承threading.Thread
        • 直接调用threading.Thread
        • Thread对象的相关方法
      • 共享队列
        • Queue相关的一些方法
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档