使用python的threading中的Thread

下面是两种基本的实现线程的方式:

第一种方式————

  1. #coding=utf-8
  2.  
  3. """
  4. thread的第一种声明及调用方式
  5. """
  6.  
  7. from threading import Thread
  8. import time
  9.  
  10. def func():
  11. while True:
  12. print time.ctime()
  13. time.sleep(1)
  14.  
  15. def func1():
  16. while True:
  17. print "func1", time.ctime()
  18. time.sleep(2)
  19.  
  20. #将要执行的方法作为参数传给Thread的构造方法
  21.  
  22. t = Thread(target=func)
  23. t.start()
  24.  
  25. t1 = Thread(target=func1)
  26. t1.start()

第二种方式————

  1. #coding=utf-8
  2.  
  3. """
  4. thread的第二种声明及调用方法
  5. """
  6.  
  7. import time
  8. from threading import Thread
  9. from time import sleep
  10.  
  11. #从Thread继承,并重写run()
  12. class myThread(Thread):
  13. def __init__(self, threadname):
  14. Thread.__init__(self, name=threadname)
  15.  
  16. def run(self):
  17. while True:
  18. print self.getName() + " " + time.ctime()
  19. time.sleep(1)
  20.  
  21. t = myThread("thread_1")
  22. t.start()
  23.  
  24. t1 = myThread("thread_2")
  25. t1.start()

接下来是:join和setDaemon的方法调用及具体区别:

join的方法调用:

  1. #coding=utf-8
  2.  
  3. """
  4. join方法的含义是:存在A主线程,B子线程,在A主线程中生成了一个子线程B,
  5. 如果子线程B调用了join方法,则主线程需要等待子线程操作结束,才能够继续往下执行,主线程会被阻塞
  6. """
  7. import time
  8. from threading import Thread
  9.  
  10. class myThread(Thread):
  11. def __init__(self, threadname):
  12. Thread.__init__(self, name = threadname)
  13.  
  14. def run(self):
  15. time.sleep(10)
  16. print self.getName() + " " + time.ctime()
  17.  
  18. def mainfunc():
  19. for i in range(5):
  20. print i
  21.  
  22. if __name__ == "__main__":
  23. t = myThread("childthread")
  24. t.start()
  25. #增加join方法的调用,则程序运行时的表现是:先子线程(会先sleep 10s,之后打印子线程的内容),再运行主线程中的打印从0到4的逻辑
  26. #不增加join方法的调用,则程序运行时的表现是:会先走主线程的打印从0到4的逻辑,之后子线程(sleep 10s,再打印子线程中的内容),但其实这里就是没有等待子线程
  27. # t.join()
  28. mainfunc()

setDaemon方法的调用:

  1. #coding=utf-8
  2.  
  3. """
  4. daemon方法的含义是:存在主线程A,和子线程B,子线程B是从主线程A中生成的
  5. 如果设置子线程B为daemon即守护进程,则主线程A不存在的话,子线程B就退出
  6. 如果没有设置子线程B为daemon,则主线程A结束运行退出之后,子线程B也不退出
  7. """
  8.  
  9. import time
  10. from threading import Thread
  11.  
  12. class myThread(Thread):
  13. def __init__(self, threadname):
  14. Thread.__init__(self, name=threadname)
  15.  
  16. def run(self):
  17. time.sleep(10)
  18. print self.getName() + " " + time.ctime()
  19.  
  20. def mainfunc():
  21. for i in range(5):
  22. print i
  23.  
  24. if __name__ == "__main__":
  25. t = myThread("zixiancheng")
  26. #不设置子线程为守护进程,则主线程退出,子线程继续运行
  27. #设置子线程为守护进程,则主线程退出,子线程直接退出
  28. #并且,需要在start之前调用setDaemon
  29. # t.setDaemon(True)
  30. t.start()
  31. mainfunc()

接下来是线程同步相关的内容:

首先是没有线程同步机制的情况下,多个线程同时操作一个公共数据:

代码如下:

  1. #coding=utf-8
  2.  
  3. """
  4. @function: test Thread的Lock
  5. @author: LiXia
  6. @date: 2017-0303
  7. """
  8.  
  9. """
  10. 所有的锁都是为了在线程之间进行通信
  11. 例如对一个公共变量进行操作,此例子为没有使用线程同步机制对公共变量进行操作
  12. """
  13.  
  14. from threading import Thread
  15. import time
  16.  
  17. data = 0
  18.  
  19. class myThread(Thread):
  20. def __init__(self):
  21. Thread.__init__(self)
  22.  
  23. def run(self):
  24. global data
  25. time.sleep(1)
  26. data += 1
  27. print self.getName() + " data: " + str(data)
  28.  
  29. if __name__ == "__main__":
  30. for i in range(5):
  31. t = myThread()
  32. t.start()

运行结果见下方:

为了能够对公共操作的数据,在特定逻辑内保持一致,需要保证在该逻辑内,只有单个线程可以操作,其他线程需要等待该线程处理结束才可以。

所以下面是关于python线程同步机制提供的指令:

1、Lock:

但是将以上代码中增加上lock处理,注意一定要增加在对公共数据的逻辑判断和处理的前面和后面,所以这里必须添加到while判断之前,释放锁需要在输出操作结束之后添加

即:

  1. #coding=utf-8
  2.  
  3. """
  4. 所有的锁都是为了在线程之间进行通信
  5. 例如对一个公共变量进行操作
  6. """
  7.  
  8. from threading import Thread
  9. import threading
  10. import time
  11.  
  12. data = 0
  13. lock = threading.Lock()
  14.  
  15. class myThread(Thread):
  16. def __init__(self):
  17. Thread.__init__(self)
  18.  
  19. def run(self):
  20. global data
  21. if lock.acquire():
  22. time.sleep(1)
  23. data += 1
  24. print self.getName() + " data: " + str(data)
  25. lock.release()
  26.  
  27. if __name__ == "__main__":
  28. for i in range(5):
  29. t = myThread()
  30. t.start()

运行结果见下方:

2、RLock

代码如下:

  1. #coding=utf-8
  2.  
  3. """
  4. 通过RLock(可重入锁)进行线程间的安全通信,RLock为可重入锁,即线程在拥有RLock之后可以继续acquire(),只要保证acquire()次数与
  5. release()次数一致即可;
  6. 继续对公共变量进行操作
  7. """
  8.  
  9. from threading import Thread
  10. import threading
  11. import time
  12.  
  13. rlock = threading.RLock()
  14. data = 0
  15.  
  16. class myThread(Thread):
  17. def __init__(self):
  18. Thread.__init__(self)
  19.  
  20. def run(self):
  21. global data
  22. if rlock.acquire():
  23. time.sleep(1)
  24. data += 1
  25. print self.getName() + " data:" + str(data)
  26.  
  27. if rlock.acquire():
  28. time.sleep(1)
  29. data -= 1
  30. print self.getName() + " data:" + str(data)
  31. rlock.release()
  32. rlock.release()
  33.  
  34. if __name__ == "__main__":
  35. for i in range(5):
  36. t = myThread()
  37. t.start()

运行结果:

3、Condition

Condition就是条件变量,condition通常与一个锁关联。

acquire([timeout])/release(): 调用关联的锁的相应方法。 
wait([timeout]): 调用这个方法将使线程进入Condition的等待池等待通知,并释放锁。使用前线程必须已获得锁定,否则将抛出异常。 
notify(): 调用这个方法将从等待池挑选一个线程并通知,收到通知的线程将自动调用acquire()尝试获得锁定(进入锁定池);其他线程仍然在等待池中。调用这个方法不会释放锁定。使用前线程必须已获得锁定,否则将抛出异常。 
notifyAll(): 调用这个方法将通知等待池中所有的线程,这些线程都将进入锁定池尝试获得锁定。调用这个方法不会释放锁定。使用前线程必须已获得锁定,否则将抛出异常。

  1. #coding=utf-8
  2.  
  3. """
  4. 以最经典的生产者和消费者的问题为例,两者需要针对一个公共的数据区域做操作,并且两端需要进行通信
  5. 生产者在生产之前,需要先占领地盘,然后开始生产,生产结束通知消费者来取;
  6. 消费者在消费的时候,也需要先占领地盘,然后开始消费,消费结束通知生产者继续生产;
  7. 当然还有多个生产者和消费者的情况,会更加复杂,可以用python的Queue来实现
  8. """
  9.  
  10. from threading import Thread
  11. import threading
  12. import time
  13. import random
  14.  
  15. product = []
  16. con = threading.Condition() #得到一个Condition的对象
  17.  
  18. #生产者线程
  19. class producerThread(Thread):
  20. def __init__(self, threadname):
  21. Thread.__init__(self, name=threadname)
  22.  
  23. def run(self):
  24. global product
  25. if con.acquire():
  26. while True:
  27. r = random.randint(0, 20)
  28. product.append(r)
  29. print "product len and product: ", self.getName(), product
  30. con.notify()
  31. con.wait()
  32. # time.sleep(2)
  33.  
  34. #消费者线程
  35. class consumerThread(Thread):
  36. def __init__(self, threadname):
  37. Thread.__init__(self, name=threadname)
  38.  
  39. def run(self):
  40. global product
  41. if con.acquire():
  42. while True:
  43. if product != []:
  44. product.pop()
  45. print "consumer len and product: ", self.getName(), product
  46. con.notify()
  47. con.wait()
  48. time.sleep(2)
  49.  
  50. if __name__ == "__main__":
  51. t1 = producerThread("producer")
  52. t2 = consumerThread("consumer")
  53.  
  54. t1.start()
  55. t2.start()

运行结果如下:

4、对多个生产者消费者支持的很好的Queue

Queue是什么?Queue实现了多生产者-多消费者的队列形式,分别包含先入先出(默认)FIFO、后进先出LIFO、以及优先级队列PriorityQueue(优先级低的先出)

Queue模块的class及exception:

  1. #coding=utf-8
  2.  
  3. """
  4. Queue的类和异常
  5. """
  6.  
  7. import Queue
  8.  
  9. q = Queue.Queue(maxsize = 0) #FIFO的Queue,maxsize即Queue的size值,maxsize≤0表示无size限制
  10.  
  11. lq = Queue.LifoQueue(maxsize = 0) #LIFO的Queue,先进后出,maxsiz的含义同上
  12.  
  13. pq = Queue.PriorityQueue(maxsize = 0) #优先级Queue,优先级低的先出,maxsize的含义同上
  14.  
  15. Queue.Empty() #当Queue的对象为空时,使用非阻塞get时会抛出异常
  16.  
  17. Queue.Full() #当Queue的对象已满时,使用非阻塞put时会抛出异常

Queue的对象:

Queue(Queue、LifoQueue、PriorityQueue)的对象提供的公共方法如下:

  1. #coding=utf-8
  2.  
  3. """
  4. Queue(Queue、LifoQueue、PriorityQueue)的对象的公共方法
  5. """
  6.  
  7. import Queue
  8.  
  9. q = Queue.Queue()
  10.  
  11. q.qsize() #获取Queue的大小
  12. q.empty() #是否为空,是则返回True,否则返回False
  13. q.full() #是否已满,是则返回True,否则返回False
  14. q.put(item[, block[, timeout]]) #put元素到Queue中,可选参数block默认值为True,timeout默认值为None,即为阻塞方法,
  15. #接上,若timeout为正值,则代表会阻塞timeout的时长之后引发一个full的异常(如果已满)
  16. q.put_nowait(item) #相当于q.put(item, False)
  17. q.get([block[, timeout]]) #get元素到Queue中,可选参数block默认值为True,timeout默认值为None,即为阻塞方法,
  18. #接上,若timeout为正数,则代表会则色timeouu的时长之后会引发一个empty的异常(如果为空)
  19. q.get_nowait() #相当于q.get(False)
  20. q.task_done() #用在Queue的消费者模式下,即用在Queue.get()方法之后,通过Queue.task_done()告诉Queue当前任务完成
  21. #如果当前join正在阻塞,则它将在所有item都被处理之后恢复
  22. q.join() #会保持阻塞直到队列中的所有item都会处理
  23. #接上,未完成的task数目会增加当一个item被add到Queue中,未完成的task数目会降低,每当消费者线程调用task_done来表示所有的
  24. #接上,work都完成了,当未完成的数目降低到0时,join就自动取消阻塞了

Queue的主要用法是什么?

看一下Queue的源码实现,然后在另一篇博客中更新一下。

  1. #coding=utf-8
  2.  
  3. """
  4. 理解Queue的用法,理解Queue衍生出来的不同的class
  5. """
  6.  
  7. from Queue import Queue
  8. from threading import Thread
  9. import time
  10. import random
  11.  
  12. q = Queue()
  13.  
  14. class producerQueue(Thread):
  15. def __init__(self, queue):
  16. Thread.__init__(self)
  17. self.queue = queue
  18.  
  19. def run(self):
  20. while True:
  21. r = random.randint(0, 99)
  22. self.queue.put(r)
  23. print self.getName() + "produce " + str(r)
  24. time.sleep(1)
  25.  
  26. class consumerQueue(Thread):
  27. def __init__(self, queue):
  28. Thread.__init__(self)
  29. self.queue = queue
  30.  
  31. def run(self):
  32. while True:
  33. r = self.queue.get()
  34. print self.getName() + "consume " + str(r)
  35. time.sleep(3)
  36. self.queue.task_done()
  37.  
  38. if __name__ == "__main__":
  39. threads = []
  40. for i in range(5):
  41. t = producerQueue(q)
  42. t.start()
  43. # threads.append(t)
  44.  
  45. for i in range(3):
  46. t = consumerQueue(q)
  47. t.start()
  48. # threads.append(t)
  49.  
  50. q.join()

之后得到的结果如下:

python——线程相关的更多相关文章

  1. python线程池ThreadPoolExecutor(上)(38)

    在前面的文章中我们已经介绍了很多关于python线程相关的知识点,比如 线程互斥锁Lock / 线程事件Event / 线程条件变量Condition 等等,而今天给大家讲解的是 线程池ThreadP ...

  2. Python之路(第四十二篇)线程相关的其他方法、join()、Thread类的start()和run()方法的区别、守护线程

    一.线程相关的其他方法 Thread实例对象的方法 # isAlive(): 返回线程是否活动的. # getName(): 返回线程名. # setName(): 设置线程名. ​ threadin ...

  3. python——线程与多线程进阶

    之前我们已经学会如何在代码块中创建新的线程去执行我们要同步执行的多个任务,但是线程的世界远不止如此.接下来,我们要介绍的是整个threading模块.threading基于Java的线程模型设计.锁( ...

  4. Python 线程、进程和协程

    python提供了两个模块来实现多线程thread 和threading ,thread 有一些缺点,在threading 得到了弥补,为了不浪费时间,所以我们直接学习threading 就可以了. ...

  5. [python] 线程简介

    参考:http://www.cnblogs.com/aylin/p/5601969.html 我是搬运工,特别感谢张岩林老师! python 线程与进程简介 进程与线程的历史 我们都知道计算机是由硬件 ...

  6. Python线程指南

    本文介绍了Python对于线程的支持,包括“学会”多线程编程需要掌握的基础以及Python两个线程标准库的完整介绍及使用示例. 注意:本文基于Python2.4完成,:如果看到不明白的词汇请记得百度谷 ...

  7. 进程 & 线程相关知识

    不管Java,C++都有进程.线程相关的内容.在这里统一整理吧. Python的线程,其实是伪线程,不能真正的并发.下面也有讲. 线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序 ...

  8. Python线程

    原文出处: AstralWind 1. 线程基础 1.1. 线程状态 线程有5种状态,状态转换的过程如下图所示: 1.2. 线程同步(锁) 多线程的优势在于可以同时运行多个任务(至少感觉起来是这样). ...

  9. Python 线程,进程

    Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元 线程不能实现多并发 只能实现伪并发 每次工作 只能是一个线程完成 由于python解释器 原生是c  原生线程 底层都会有一把 ...

随机推荐

  1. Hadoop 3.0 安装

    1.      下载Hadoop 3.0 http://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/common/hadoop-3.0.0/hadoop-3. ...

  2. 机器学习进阶-图像金字塔与轮廓检测-图像金字塔-(**高斯金字塔) 1.cv2.pyrDown(对图片做向下采样) 2.cv2.pyrUp(对图片做向上采样)

    1.cv2.pyrDown(src)  对图片做向下采样操作,通常也可以做模糊化处理 参数说明:src表示输入的图片 2.cv2.pyrUp(src) 对图片做向上采样操作 参数说明:src表示输入的 ...

  3. Go的50度灰:Golang新开发者要注意的陷阱和常见错误(转)

    目录 [−] 初级 开大括号不能放在单独的一行 未使用的变量 未使用的Imports 简式的变量声明仅可以在函数内部使用 使用简式声明重复声明变量 偶然的变量隐藏Accidental Variable ...

  4. 遍历DOM树,理解更新范围

    在JavaScript中,如果需求对多个元素重复进行同样的操作,就需要写一个循环来遍历选中的所有元素. 在jQuery中,当选择器返回了多个元素时,可以使用一个方法来更新所有的元素,不再需要使用循环. ...

  5. KVM虚拟化技术(一)虚拟化简介

    一 .虚拟化 虚拟化是指计算机元件在虚拟的基础上而不是真实的基础上运行.虚拟化技术可以扩大硬件的容量,简化软件的重新配置过程.CPU的虚拟化技术可以单CPU模 拟多CPU并行,允许一个平台同时运行多个 ...

  6. 获取jdk支持的编码类型

    //获取jdk支持的编码类型 Map<String,Charset> maps = Charset.availableCharsets(); for(Map.Entry<String ...

  7. js 高效拼接字符串

    <script>//如果我们大量使用+=进行字符串拼接的话,将会使界面失去响应(卡死状态) //高效拼接字符串 var StringBuilder=function() { this.da ...

  8. delphi 实现用户自定义通知(User Notification)

    unit Form_Main; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, Sy ...

  9. eclipse中配置Tomcat服务器以及新建项目

    eclipse配置Tomcat服务器 http://jingyan.baidu.com/article/ca2d939dd90183eb6d31ce79.html eclipse中配置Tomcat服务 ...

  10. 传输层——TCP报文头介绍

    16位源端口号 16位目的端口号 32位序列号 32位确认序列号 4位头部长度 保留6位 U R G A C K P S H R S T S Y N F I N 16位窗口大小 16位检验和 16位紧 ...