多线程类似于同时执行多个不同程序,多线程运行有如下优点:

  • 使用线程可以把占据长时间的程序中的任务放到后台去处理。
  • 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
  • 程序的运行速度可能加快
  • 在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。

Python中使用线程有两种方式:函数或者用类来包装线程对象。

函数式:调用thread模块中的start_new_thread()函数来产生新线程。语法如下:

  1. thread.start_new_thread ( function, args[, kwargs] )

参数说明:

  • function - 线程函数。
  • args - 传递给线程函数的参数,他必须是个tuple类型。
  • kwargs - 可选参数。

使用Thread模块创建线程

  1. import _thread
  2. import time
  3.  
  4. # 定义一个函数
  5. def print_time(threadName , delay):
  6. count = 0
  7. while count < 5:
  8. time.sleep(delay)
  9. count += 1
  10. print(threadName,count)
  11.  
  12. #创建两个线程
  13. try:
  14. _thread.start_new_thread(print_time,("Thread-1",2))
  15. _thread.start_new_thread(print_time,("Thread-2",4))
  16. except:
  17. print("Error : unable to start thread")
  18. while 1:
  19. pass

结果:

  1. Thread-1 1
  2. Thread-1 2
  3. Thread-2 1
  4. Thread-1 3
  5. Thread-1 4
  6. Thread-2 2
  7. Thread-1 5
  8. Thread-2 3
  9. Thread-2 4
  10. Thread-2 5

使用Threading模块创建线程

  1. import threading
  2. import time
  3.  
  4. exitFlag = 0
  5.  
  6. class myThread(threading.Thread): # 继承父类threading.Thread
  7. def __init__(self, threadID, name, counter):
  8. threading.Thread.__init__(self)
  9. self.threadID = threadID
  10. self.name = name
  11. self.counter = counter
  12.  
  13. def run(self): # 把要执行的代码写到run函数里面 线程在创建后会直接运行run函数
  14. print("Starting " + self.name)
  15. print_time(self.name, self.counter, 5)
  16. print("Exiting " + self.name)
  17.  
  18. def print_time(threadName, delay, counter):
  19. while counter:
  20. if exitFlag:
  21. (threading.Thread).exit()
  22. time.sleep(delay)
  23. print("%s: %s" % (threadName, time.ctime(time.time())))
  24. counter -= 1
  25.  
  26. # 创建新线程
  27. thread1 = myThread(1, "Thread-1", 1)
  28. thread2 = myThread(2, "Thread-2", 2)
  29.  
  30. # 开启线程
  31. thread1.start()
  32. thread2.start()
  33.  
  34. print("Exiting Main Thread")

结果:

  1. Starting Thread-1
  2. Starting Thread-2
  3. Exiting Main Thread
  4. Thread-1: Thu Mar 21 09:10:03 2013
  5. Thread-1: Thu Mar 21 09:10:04 2013
  6. Thread-2: Thu Mar 21 09:10:04 2013
  7. Thread-1: Thu Mar 21 09:10:05 2013
  8. Thread-1: Thu Mar 21 09:10:06 2013
  9. Thread-2: Thu Mar 21 09:10:06 2013
  10. Thread-1: Thu Mar 21 09:10:07 2013
  11. Exiting Thread-1
  12. Thread-2: Thu Mar 21 09:10:08 2013
  13. Thread-2: Thu Mar 21 09:10:10 2013
  14. Thread-2: Thu Mar 21 09:10:12 2013
  15. Exiting Thread-2

线程同步

如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步。

使用Thread对象的Lock和Rlock可以实现简单的线程同步,这两个对象都有acquire方法和release方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到acquire和release方法之间。如下:

多线程的优势在于可以同时运行多个任务(至少感觉起来是这样)。但是当线程需要共享数据时,可能存在数据不同步的问题。

考虑这样一种情况:一个列表里所有元素都是0,线程"set"从后向前把所有元素改成1,而线程"print"负责从前往后读取列表并打印。

那么,可能线程"set"开始改的时候,线程"print"便来打印列表了,输出就成了一半0一半1,这就是数据的不同步。为了避免这种情况,引入了锁的概念。

锁有两种状态——锁定和未锁定。每当一个线程比如"set"要访问共享数据时,必须先获得锁定;如果已经有别的线程比如"print"获得锁定了,那么就让线程"set"暂停,也就是同步阻塞;等到线程"print"访问完毕,释放锁以后,再让线程"set"继续。

经过这样的处理,打印列表时要么全部输出0,要么全部输出1,不会再出现一半0一半1的尴尬场面。

  1. import threading
  2. import time
  3.  
  4. class myThread(threading.Thread):
  5. def __init__(self, threadID, name, counter):
  6. threading.Thread.__init__(self)
  7. self.threadID = threadID
  8. self.name = name
  9. self.counter = counter
  10.  
  11. def run(self):
  12. print("Starting " + self.name)
  13. # 获得锁,成功获得锁定后返回True
  14. # 可选的timeout参数不填时将一直阻塞直到获得锁定
  15. # 否则超时后将返回False
  16. threadLock.acquire()
  17. print_time(self.name, self.counter, 3)
  18. # 释放锁
  19. threadLock.release()
  20.  
  21. def print_time(threadName, delay, counter):
  22. while counter:
  23. time.sleep(delay)
  24. print("%s: %s" % (threadName, time.ctime(time.time())))
  25. counter -= 1
  26.  
  27. threadLock = threading.Lock()
  28. threads = []
  29.  
  30. # 创建新线程
  31. thread1 = myThread(1, "Thread-1", 1)
  32. thread2 = myThread(2, "Thread-2", 2)
  33.  
  34. # 开启新线程
  35. thread1.start()
  36. thread2.start()
  37.  
  38. # 添加线程到线程列表
  39. threads.append(thread1)
  40. threads.append(thread2)
  41.  
  42. # 等待所有线程完成
  43. for t in threads:
  44. t.join()
  45. print("Exiting Main Thread")

结果:

  1. Starting Thread-1
  2. Starting Thread-2
  3. Thread-1: Tue Apr 24 11:09:33 2018
  4. Thread-1: Tue Apr 24 11:09:34 2018
  5. Thread-1: Tue Apr 24 11:09:35 2018
  6. Thread-2: Tue Apr 24 11:09:37 2018
  7. Thread-2: Tue Apr 24 11:09:39 2018
  8. Thread-2: Tue Apr 24 11:09:41 2018
  9. Exiting Main Thread

线程优先级队列( Queue)

Python的Queue模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue。这些队列都实现了锁原语,能够在多线程中直接使用。可以使用队列来实现线程间的同步。

Queue模块中的常用方法:

  • Queue.qsize() 返回队列的大小
  • Queue.empty() 如果队列为空,返回True,反之False
  • Queue.full() 如果队列满了,返回True,反之False
  • Queue.full 与 maxsize 大小对应
  • Queue.get([block[, timeout]])获取队列,timeout等待时间
  • Queue.get_nowait() 相当Queue.get(False)
  • Queue.put(item) 写入队列,timeout等待时间
  • Queue.put_nowait(item) 相当Queue.put(item, False)
  • Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号
  • Queue.join() 实际上意味着等到队列为空,再执行别的操作
  1. import queue
  2. import threading
  3. import time
  4.  
  5. exitFlag = 0
  6.  
  7. class myThread(threading.Thread):
  8. def __init__(self, threadID, name, q):
  9. threading.Thread.__init__(self)
  10. self.threadID = threadID
  11. self.name = name
  12. self.q = q
  13.  
  14. def run(self):
  15. print("Starting " + self.name)
  16. process_data(self.name, self.q)
  17. print("Exiting " + self.name)
  18.  
  19. def process_data(threadName, q):
  20. while not exitFlag:
  21. queueLock.acquire()
  22. if not workQueue.empty():
  23. data = q.get()
  24. queueLock.release()
  25. print("%s processing %s" % (threadName, data))
  26. else:
  27. queueLock.release()
  28. time.sleep(1)
  29.  
  30. threadList = ["Thread-1", "Thread-2", "Thread-3"]
  31. nameList = ["One", "Two", "Three", "Four", "Five"]
  32. queueLock = threading.Lock()
  33. workQueue = queue.Queue(10)
  34. threads = []
  35. threadID = 1
  36.  
  37. # 创建新线程
  38. for tName in threadList:
  39. thread = myThread(threadID, tName, workQueue)
  40. thread.start()
  41. threads.append(thread)
  42. threadID += 1
  43.  
  44. # 填充队列
  45. queueLock.acquire()
  46. for word in nameList:
  47. workQueue.put(word)
  48. queueLock.release()
  49.  
  50. # 等待队列清空
  51. while not workQueue.empty():
  52. pass
  53.  
  54. # 通知线程是时候退出
  55. exitFlag = 1
  56.  
  57. # 等待所有线程完成
  58. for t in threads:
  59. t.join()
  60. print("Exiting Main Thread")

结果:

  1. Starting Thread-1
  2. Starting Thread-2
  3. Starting Thread-3
  4. Thread-2 processing One
  5. Thread-1 processing Two
  6. Thread-3 processing Three
  7. Thread-3 processing Four
  8. Thread-1 processing Five
  9. Exiting Thread-2
  10. Exiting Thread-3
  11. Exiting Thread-1
  12. Exiting Main Thread

Python多线程基本操作的更多相关文章

  1. 进程,线程,GIL,Python多线程,生产者消费者模型都是什么鬼

    1. 操作系统基本知识,进程,线程 CPU是计算机的核心,承担了所有的计算任务: 操作系统是计算机的管理者,它负责任务的调度.资源的分配和管理,统领整个计算机硬件:那么操作系统是如何进行任务调度的呢? ...

  2. 浅析Python多线程

    学习Python多线程的资料很多,吐槽Python多线程的博客也不少.本文主要介绍Python多线程实际应用,且假设读者已经了解多线程的基本概念.如果读者对进程线程概念不甚了解,可参见知名博主 阮一峰 ...

  3. python多线程学习记录

    1.多线程的创建 import threading t = t.theading.Thread(target, args--) t.SetDeamon(True)//设置为守护进程 t.start() ...

  4. python多线程编程

    Python多线程编程中常用方法: 1.join()方法:如果一个线程或者在函数执行的过程中调用另一个线程,并且希望待其完成操作后才能执行,那么在调用线程的时就可以使用被调线程的join方法join( ...

  5. Python 多线程教程:并发与并行

    转载于: https://my.oschina.net/leejun2005/blog/398826 在批评Python的讨论中,常常说起Python多线程是多么的难用.还有人对 global int ...

  6. python多线程

    python多线程有两种用法,一种是在函数中使用,一种是放在类中使用 1.在函数中使用 定义空的线程列表 threads=[] 创建线程 t=threading.Thread(target=函数名,a ...

  7. python 多线程就这么简单(转)

    多线程和多进程是什么自行google补脑 对于python 多线程的理解,我花了很长时间,搜索的大部份文章都不够通俗易懂.所以,这里力图用简单的例子,让你对多线程有个初步的认识. 单线程 在好些年前的 ...

  8. python 多线程就这么简单(续)

    之前讲了多线程的一篇博客,感觉讲的意犹未尽,其实,多线程非常有意思.因为我们在使用电脑的过程中无时无刻都在多进程和多线程.我们可以接着之前的例子继续讲.请先看我的上一篇博客. python 多线程就这 ...

  9. python多线程监控指定目录

    import win32file import tempfile import threading import win32con import os dirs=["C:\\WINDOWS\ ...

随机推荐

  1. [elk]elasticsearch dsl语句

    例子1 统计1,有唱歌兴趣的 2,按年龄分组 3,求每组平均年龄 4,按平均年龄降序排序 sql转为dsl例子 # 每种型号车的颜色数 > 1的 SELECT model,COUNT(DISTI ...

  2. 【Java】NO.80.Note.1.Java.1.001-【Java 各种特性概念】

    1.0.0 Summary Tittle:[Java]NO.80.Note.1.Java.1.001-[Java 各种特性概念] Style:Java Series:Java Since:2018-0 ...

  3. Linux平台 Oracle 18c RAC安装Part3:DB配置

    四.DB(Database)配置 4.1 解压DB的安装包 4.2 DB软件配置 4.3 ASMCA创建磁盘组 4.4 DBCA建库 4.5 验证crsctl的状态 Linux平台 Oracle 18 ...

  4. 使用msf对tomcat测试

    1.1 使用nmap命令对目标主机进行扫描.单击桌面空白处,右键菜单选择"在终端中打开". 1.2 在终端中输入命令"nmap –sV 192.168.1.3" ...

  5. linux----------linux的scp命令介绍

    1.scp是有Security的文件copy,基于ssh登录. 命令基本格式: scp [OPTIONS] file_source file_target OPTIONS: -v 和大多数 linux ...

  6. Hbase伪分布式安装

    前面的文章已经讲过hadoop伪分布式安装,这里直接介绍hbase伪分布式安装. 1. 下载hbase 版本hbase 1.2.6 2. 解压hbase 3. 修改hbase-env.sh 新增如下内 ...

  7. DataGridView 访问任意行不崩溃

    int index= this.dataGridView1.rows.Add(); 先执行这行代码,然后访问任意行,不崩溃, 赋值不存在的行,只是不显示,或者无值. 什么原理呢? 一些其他 priva ...

  8. VXLAN

    网络协议栈 应用层:Telnet FTP HTTP SMTP... 传输层:TCP UDP 网络层:IP ICMP 物理链路层:ARP 以太网头(源目的MAC) | IP头(源目的IP) | TCP头 ...

  9. 内置函数_map、filter

     1.map   #循环帮你调用函数 map(makir,dir_names)     #生成器,结果是一个内存地址.为了节省内存,每次循环时,就按照定义的规则去生成一个数据,循环一次释放一次生成的数 ...

  10. tomcat 修改内存配置

    1.linux 下调整tomcat的内存设置修改bin目录下catalina.sh文件在cygwin=false之上添加以下语句JAVA_OPTS="-Xms1024m -Xmx4096m ...