Python多线程基本操作
多线程类似于同时执行多个不同程序,多线程运行有如下优点:
- 使用线程可以把占据长时间的程序中的任务放到后台去处理。
- 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
- 程序的运行速度可能加快
- 在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。
Python中使用线程有两种方式:函数或者用类来包装线程对象。
函数式:调用thread模块中的start_new_thread()函数来产生新线程。语法如下:
- thread.start_new_thread ( function, args[, kwargs] )
参数说明:
- function - 线程函数。
- args - 传递给线程函数的参数,他必须是个tuple类型。
- kwargs - 可选参数。
使用Thread模块创建线程
- import _thread
- import time
- # 定义一个函数
- def print_time(threadName , delay):
- count = 0
- while count < 5:
- time.sleep(delay)
- count += 1
- print(threadName,count)
- #创建两个线程
- try:
- _thread.start_new_thread(print_time,("Thread-1",2))
- _thread.start_new_thread(print_time,("Thread-2",4))
- except:
- print("Error : unable to start thread")
- while 1:
- pass
结果:
- Thread-1 1
- Thread-1 2
- Thread-2 1
- Thread-1 3
- Thread-1 4
- Thread-2 2
- Thread-1 5
- Thread-2 3
- Thread-2 4
- Thread-2 5
使用Threading模块创建线程
- import threading
- import time
- exitFlag = 0
- class myThread(threading.Thread): # 继承父类threading.Thread
- def __init__(self, threadID, name, counter):
- threading.Thread.__init__(self)
- self.threadID = threadID
- self.name = name
- self.counter = counter
- def run(self): # 把要执行的代码写到run函数里面 线程在创建后会直接运行run函数
- print("Starting " + self.name)
- print_time(self.name, self.counter, 5)
- print("Exiting " + self.name)
- def print_time(threadName, delay, counter):
- while counter:
- if exitFlag:
- (threading.Thread).exit()
- time.sleep(delay)
- print("%s: %s" % (threadName, time.ctime(time.time())))
- counter -= 1
- # 创建新线程
- thread1 = myThread(1, "Thread-1", 1)
- thread2 = myThread(2, "Thread-2", 2)
- # 开启线程
- thread1.start()
- thread2.start()
- print("Exiting Main Thread")
结果:
- Starting Thread-1
- Starting Thread-2
- Exiting Main Thread
- Thread-1: Thu Mar 21 09:10:03 2013
- Thread-1: Thu Mar 21 09:10:04 2013
- Thread-2: Thu Mar 21 09:10:04 2013
- Thread-1: Thu Mar 21 09:10:05 2013
- Thread-1: Thu Mar 21 09:10:06 2013
- Thread-2: Thu Mar 21 09:10:06 2013
- Thread-1: Thu Mar 21 09:10:07 2013
- Exiting Thread-1
- Thread-2: Thu Mar 21 09:10:08 2013
- Thread-2: Thu Mar 21 09:10:10 2013
- Thread-2: Thu Mar 21 09:10:12 2013
- 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的尴尬场面。
- import threading
- import time
- class myThread(threading.Thread):
- def __init__(self, threadID, name, counter):
- threading.Thread.__init__(self)
- self.threadID = threadID
- self.name = name
- self.counter = counter
- def run(self):
- print("Starting " + self.name)
- # 获得锁,成功获得锁定后返回True
- # 可选的timeout参数不填时将一直阻塞直到获得锁定
- # 否则超时后将返回False
- threadLock.acquire()
- print_time(self.name, self.counter, 3)
- # 释放锁
- threadLock.release()
- def print_time(threadName, delay, counter):
- while counter:
- time.sleep(delay)
- print("%s: %s" % (threadName, time.ctime(time.time())))
- counter -= 1
- threadLock = threading.Lock()
- threads = []
- # 创建新线程
- thread1 = myThread(1, "Thread-1", 1)
- thread2 = myThread(2, "Thread-2", 2)
- # 开启新线程
- thread1.start()
- thread2.start()
- # 添加线程到线程列表
- threads.append(thread1)
- threads.append(thread2)
- # 等待所有线程完成
- for t in threads:
- t.join()
- print("Exiting Main Thread")
结果:
- Starting Thread-1
- Starting Thread-2
- Thread-1: Tue Apr 24 11:09:33 2018
- Thread-1: Tue Apr 24 11:09:34 2018
- Thread-1: Tue Apr 24 11:09:35 2018
- Thread-2: Tue Apr 24 11:09:37 2018
- Thread-2: Tue Apr 24 11:09:39 2018
- Thread-2: Tue Apr 24 11:09:41 2018
- 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() 实际上意味着等到队列为空,再执行别的操作
- import queue
- import threading
- import time
- exitFlag = 0
- class myThread(threading.Thread):
- def __init__(self, threadID, name, q):
- threading.Thread.__init__(self)
- self.threadID = threadID
- self.name = name
- self.q = q
- def run(self):
- print("Starting " + self.name)
- process_data(self.name, self.q)
- print("Exiting " + self.name)
- def process_data(threadName, q):
- while not exitFlag:
- queueLock.acquire()
- if not workQueue.empty():
- data = q.get()
- queueLock.release()
- print("%s processing %s" % (threadName, data))
- else:
- queueLock.release()
- time.sleep(1)
- threadList = ["Thread-1", "Thread-2", "Thread-3"]
- nameList = ["One", "Two", "Three", "Four", "Five"]
- queueLock = threading.Lock()
- workQueue = queue.Queue(10)
- threads = []
- threadID = 1
- # 创建新线程
- for tName in threadList:
- thread = myThread(threadID, tName, workQueue)
- thread.start()
- threads.append(thread)
- threadID += 1
- # 填充队列
- queueLock.acquire()
- for word in nameList:
- workQueue.put(word)
- queueLock.release()
- # 等待队列清空
- while not workQueue.empty():
- pass
- # 通知线程是时候退出
- exitFlag = 1
- # 等待所有线程完成
- for t in threads:
- t.join()
- print("Exiting Main Thread")
结果:
- Starting Thread-1
- Starting Thread-2
- Starting Thread-3
- Thread-2 processing One
- Thread-1 processing Two
- Thread-3 processing Three
- Thread-3 processing Four
- Thread-1 processing Five
- Exiting Thread-2
- Exiting Thread-3
- Exiting Thread-1
- Exiting Main Thread
Python多线程基本操作的更多相关文章
- 进程,线程,GIL,Python多线程,生产者消费者模型都是什么鬼
1. 操作系统基本知识,进程,线程 CPU是计算机的核心,承担了所有的计算任务: 操作系统是计算机的管理者,它负责任务的调度.资源的分配和管理,统领整个计算机硬件:那么操作系统是如何进行任务调度的呢? ...
- 浅析Python多线程
学习Python多线程的资料很多,吐槽Python多线程的博客也不少.本文主要介绍Python多线程实际应用,且假设读者已经了解多线程的基本概念.如果读者对进程线程概念不甚了解,可参见知名博主 阮一峰 ...
- python多线程学习记录
1.多线程的创建 import threading t = t.theading.Thread(target, args--) t.SetDeamon(True)//设置为守护进程 t.start() ...
- python多线程编程
Python多线程编程中常用方法: 1.join()方法:如果一个线程或者在函数执行的过程中调用另一个线程,并且希望待其完成操作后才能执行,那么在调用线程的时就可以使用被调线程的join方法join( ...
- Python 多线程教程:并发与并行
转载于: https://my.oschina.net/leejun2005/blog/398826 在批评Python的讨论中,常常说起Python多线程是多么的难用.还有人对 global int ...
- python多线程
python多线程有两种用法,一种是在函数中使用,一种是放在类中使用 1.在函数中使用 定义空的线程列表 threads=[] 创建线程 t=threading.Thread(target=函数名,a ...
- python 多线程就这么简单(转)
多线程和多进程是什么自行google补脑 对于python 多线程的理解,我花了很长时间,搜索的大部份文章都不够通俗易懂.所以,这里力图用简单的例子,让你对多线程有个初步的认识. 单线程 在好些年前的 ...
- python 多线程就这么简单(续)
之前讲了多线程的一篇博客,感觉讲的意犹未尽,其实,多线程非常有意思.因为我们在使用电脑的过程中无时无刻都在多进程和多线程.我们可以接着之前的例子继续讲.请先看我的上一篇博客. python 多线程就这 ...
- python多线程监控指定目录
import win32file import tempfile import threading import win32con import os dirs=["C:\\WINDOWS\ ...
随机推荐
- [elk]elasticsearch dsl语句
例子1 统计1,有唱歌兴趣的 2,按年龄分组 3,求每组平均年龄 4,按平均年龄降序排序 sql转为dsl例子 # 每种型号车的颜色数 > 1的 SELECT model,COUNT(DISTI ...
- 【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 ...
- 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 ...
- 使用msf对tomcat测试
1.1 使用nmap命令对目标主机进行扫描.单击桌面空白处,右键菜单选择"在终端中打开". 1.2 在终端中输入命令"nmap –sV 192.168.1.3" ...
- linux----------linux的scp命令介绍
1.scp是有Security的文件copy,基于ssh登录. 命令基本格式: scp [OPTIONS] file_source file_target OPTIONS: -v 和大多数 linux ...
- Hbase伪分布式安装
前面的文章已经讲过hadoop伪分布式安装,这里直接介绍hbase伪分布式安装. 1. 下载hbase 版本hbase 1.2.6 2. 解压hbase 3. 修改hbase-env.sh 新增如下内 ...
- DataGridView 访问任意行不崩溃
int index= this.dataGridView1.rows.Add(); 先执行这行代码,然后访问任意行,不崩溃, 赋值不存在的行,只是不显示,或者无值. 什么原理呢? 一些其他 priva ...
- VXLAN
网络协议栈 应用层:Telnet FTP HTTP SMTP... 传输层:TCP UDP 网络层:IP ICMP 物理链路层:ARP 以太网头(源目的MAC) | IP头(源目的IP) | TCP头 ...
- 内置函数_map、filter
1.map #循环帮你调用函数 map(makir,dir_names) #生成器,结果是一个内存地址.为了节省内存,每次循环时,就按照定义的规则去生成一个数据,循环一次释放一次生成的数 ...
- tomcat 修改内存配置
1.linux 下调整tomcat的内存设置修改bin目录下catalina.sh文件在cygwin=false之上添加以下语句JAVA_OPTS="-Xms1024m -Xmx4096m ...