多线程的使用

多线程

前言

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

使用多线程

继承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() 实际上意味着等到队列为空,再执行别的操作

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Java学习网

Java类加载机制的七个阶段,加载、验证、准备、解析、初始化、使用、卸载

当我们的Java代码编译完成后,会生成对应的 class 文件。接着我们运行java Demo命令的时候,我们其实是启动了JVM 虚拟机执行 class 字节码...

6963
来自专栏mathor

第六届蓝桥杯决赛B组C/C++——密文搜索

1672
来自专栏闪电gogogo的专栏

Python初学——多进程Multiprocessing

1.1 什么是 Multiprocessing 多线程在同一时间只能处理一个任务。 可把任务平均分配给每个核,而每个核具有自己的运算空间。 1.2 添加进程 P...

3678
来自专栏视觉求索无尽也

【Python】Python知识点总结

字典{key:value,key:value},dict(key=value,key=value):

4291
来自专栏海说

深入理解计算机系统(3.3)---数据传送(或者说复制)指令详解

  上一章我们已经介绍了汇编语言的基础部分,包括数据格式、寄存器以及操作数的标识方式,接下来我们就应该去认识一下汇编语言当中的各个指令了。这些指令大多数都非常简...

1005
来自专栏C/C++基础

函数调用时堆栈的变化情况

函数的正常运行必然要利用堆栈,至少,函数的返回地址是保存在堆栈上的。函数一般要利用参数,而且内部也会用到局部变量,在对表达式进行求值时,编译器还会生成一些无名临...

741
来自专栏大闲人柴毛毛

深入JVM——OOM异常解析

JVM对象访问解析 对象访问过程的内存情况 public void function(){ Object obj = new Object(); } f...

39411
来自专栏海说

深入理解计算机系统(3.3)---数据传送(或者说复制)指令详解

  上一章我们已经介绍了汇编语言的基础部分,包括数据格式、寄存器以及操作数的标识方式,接下来我们就应该去认识一下汇编语言当中的各个指令了。这些指令大多数都非常简...

1123
来自专栏章鱼的慢慢技术路

Linux操作_grep/egrep工具的使用

1765
来自专栏desperate633

深入理解Java Runtime Area Java运行时数据区Java Runtime Area的分类从线程的角度理解Java Runtime Area从存储内容理解Java Runtime Are

具体的每个区域的内容和特点可以参考《深入理解Java虚拟机》,此书已经讲的很详细了。 下面我们对这几个数据区域进行分类,分别从不同的视角来分析,加深我们的理解

761

扫码关注云+社区

领取腾讯云代金券