Python3 多线程

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

使用线程可以把占据长时间的程序中的任务放到后台去处理。

用户界面可以更加吸引人,比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度。

程序的运行速度可能加快。

在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。

每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

每个线程都有他自己的一组CPU寄存器,称为线程的上下文,该上下文反映了线程上次运行该线程的CPU寄存器的状态。

指令指针和堆栈指针寄存器是线程上下文中两个最重要的寄存器,线程总是在进程得到上下文中运行的,这些地址都用于标志拥有线程的进程地址空间中的内存。

线程可以被抢占(中断)。

在其他线程正在运行时,线程可以暂时搁置(也称为睡眠) -- 这就是线程的退让。

线程可以分为:

内核线程:由操作系统内核创建和撤销。

用户线程:不需要内核支持而在用户程序中实现的线程。

Python3 线程中常用的两个模块为:

_thread

threading(推荐使用)

thread 模块已被废弃。用户可以使用 threading 模块代替。所以,在 Python3 中不能再使用"thread" 模块。为了兼容性,Python3 将 thread 重命名为 "_thread"。

开始学习Python线程

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

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

_thread.start_new_thread ( function, args[, kwargs] )

参数说明:

function - 线程函数。

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

kwargs - 可选参数。

实例

#!/usr/bin/python3

import _thread

import time

# 为线程定义一个函数

def print_time( threadName, delay):

count = 0

while count < 5:

time.sleep(delay)

count += 1

print ("%s: %s" % ( threadName, time.ctime(time.time()) ))

# 创建两个线程

try:

_thread.start_new_thread( print_time, ("Thread-1", 2, ) )

_thread.start_new_thread( print_time, ("Thread-2", 4, ) )

except:

print ("Error: 无法启动线程")

while 1:

pass

执行以上程序输出结果如下:

Thread-1: Wed Apr 6 11:36:31 2016

Thread-1: Wed Apr 6 11:36:33 2016

Thread-2: Wed Apr 6 11:36:33 2016

Thread-1: Wed Apr 6 11:36:35 2016

Thread-1: Wed Apr 6 11:36:37 2016

Thread-2: Wed Apr 6 11:36:37 2016

Thread-1: Wed Apr 6 11:36:39 2016

Thread-2: Wed Apr 6 11:36:41 2016

Thread-2: Wed Apr 6 11:36:45 2016

Thread-2: Wed Apr 6 11:36:49 2016

执行以上程后可以按下 ctrl-c 退出。

线程模块

Python3 通过两个标准库 _thread 和 threading 提供对线程的支持。

_thread 提供了低级别的、原始的线程以及一个简单的锁,它相比于 threading 模块的功能还是比较有限的。

threading 模块除了包含 _thread 模块中的所有方法外,还提供的其他方法:

threading.currentThread(): 返回当前的线程变量。

threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。

threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法:

run(): 用以表示线程活动的方法。

start():启动线程活动。

join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。

isAlive(): 返回线程是否活动的。

getName(): 返回线程名。

setName(): 设置线程名。

使用 threading 模块创建线程

我们可以通过直接从 threading.Thread 继承创建一个新的子类,并实例化后调用 start() 方法启动新线程,即它调用了线程的 run() 方法:

实例

#!/usr/bin/python3

import threading

import time

exitFlag = 0

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 ("开始线程:" + self.name)

print_time(self.name, self.counter, 5)

print ("退出线程:" + self.name)

def print_time(threadName, delay, counter):

while counter:

if exitFlag:

threadName.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()

thread1.join()

thread2.join()

print ("退出主线程")

以上程序执行结果如下;

开始线程:Thread-1

开始线程:Thread-2

Thread-1: Wed Apr 6 11:46:46 2016

Thread-1: Wed Apr 6 11:46:47 2016

Thread-2: Wed Apr 6 11:46:47 2016

Thread-1: Wed Apr 6 11:46:48 2016

Thread-1: Wed Apr 6 11:46:49 2016

Thread-2: Wed Apr 6 11:46:49 2016

Thread-1: Wed Apr 6 11:46:50 2016

退出线程:Thread-1

Thread-2: Wed Apr 6 11:46:51 2016

Thread-2: Wed Apr 6 11:46:53 2016

Thread-2: Wed Apr 6 11:46:55 2016

退出线程: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的尴尬场面。

实例

#!/usr/bin/python3

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 ("开启线程: " + self.name)

# 获取锁,用于线程同步

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 ("退出主线程")

执行以上程序,输出结果为:

开启线程: Thread-1

开启线程: Thread-2

Thread-1: Wed Apr 6 11:52:57 2016

Thread-1: Wed Apr 6 11:52:58 2016

Thread-1: Wed Apr 6 11:52:59 2016

Thread-2: Wed Apr 6 11:53:01 2016

Thread-2: Wed Apr 6 11:53:03 2016

Thread-2: Wed Apr 6 11:53:05 2016

退出主线程

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

实例

#!/usr/bin/python3

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 ("开启线程:" + self.name)

process_data(self.name, self.q)

print ("退出线程:" + 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 ("退出主线程")

以上程序执行结果:

开启线程:Thread-1

开启线程:Thread-2

开启线程:Thread-3

Thread-3 processing One

Thread-1 processing Two

Thread-2 processing Three

Thread-3 processing Four

Thread-1 processing Five

退出线程:Thread-3

退出线程:Thread-2

退出线程:Thread-1

退出主线程

python3多线程第三方库_Python3 多线程相关推荐

  1. python3多线程第三方库_Python3标准库:concurrent.futures管理并发任务池

    Python Python开发 Python语言 Python3标准库:concurrent.futures管理并发任务池 1. concurrent.futures管理并发任务池 concurren ...

  2. python基础代码库-python3.4第三方库的安装?python基础代码库

    python怎么安装下载模块 python安装下载模块的:1.按盘上的[win r]快,打开运行窗口:2.输入cmd,点击定]:3.在打开的命令提示符中执行[pip install 模块名]命令即可. ...

  3. python3多线程第三方库_Python之多线程爬虫抓取网页图片的示例代码

    目标 嗯,我们知道搜索或浏览网站时会有很多精美.漂亮的图片. 我们下载的时候,得鼠标一个个下载,而且还翻页. 那么,有没有一种方法,可以使用非人工方式自动识别并下载图片.美美哒. 那么请使用pytho ...

  4. python多线程实现方法_Python3 多线程的两种实现方式

    最近学习 Python3 ,希望能掌握多线程的使用,在此做个笔记.同时也希望Python 牛人指点错误.关于线程的概念,前面简单总结了一下 java 的多线程,传送门:java 多线程概念,三种创建多 ...

  5. python3安装第三方库教程

    测试环境:win10 64bit+python3.6+cmd ------------------------------------------------------ 1. 安装第三方库 这里安装 ...

  6. python3.6安装库_python3.6怎么安装库

    Python3.6安装第三方库有两种方式: 1. 使用 pip 命令行工具在线下载你需要的第三方库 2. 手动下载第三方库,再使用 pip 命令安装 1. 使用 pip 命令行工具在线下载你需要的第三 ...

  7. python3线程池爬虫_python3多线程爬虫中如何变量?

    我们可以把待处理的程序看成一批需要配送的包裹,包裹在不同的货架上摆放.单人整理会比几个人一起摆放要慢的多.同样在计算机处理中,单凭借一个程序打开运行是远远不够用的,我们需要同时处理多个事物,所以多线程 ...

  8. python3多线程和多进程_Python3 多线程、多进程

    python中的线程是假线程,不同线程之间的切换是需要耗费资源的,因为需要存储线程的上下文,不断的切换就会耗费资源.. python多线程适合io操作密集型的任务(如socket server 网络并 ...

  9. mac python3.8上怎么安装pygame 第三方库_Python3.8安装Pygame Python3.8安装Pygame教程步骤详解...

    想了解Python3.8安装Pygame教程步骤详解的相关内容吗,孤傲小二~阿沐在本文为您仔细讲解Python3.8安装Pygame的相关知识和一些Code实例,欢迎阅读和指正,我们先划重点:Pyth ...

最新文章

  1. 三端可调稳压集成电路LM317的多种应用电路
  2. snowflake算法 php,Snowflake —— 分布式全局唯一 id 生成算法
  3. 【深度学习】深度学习语义分割理论与实战指南.pdf
  4. python 可视化饼图_Python可视化学习(饼状图,坐标系...)
  5. 汇编语言 -第十一章
  6. 声速的测量的实验原理和应用_CEMS烟气在线分析仪测量原理计经典应用
  7. 原始套接字抓取所有以太网数据包与分析
  8. JavaScript学习五
  9. android 判断两个整数,【tips】判断两个整数是否是同一个数量级
  10. 拓端tecdat|R语言使用二元回归将序数数据建模为多元GLM
  11. 【转】在唯一密钥属性“value”设置为“***”时,无法添加类型为“add”的重复集合项解决方法
  12. html5标签含义元素周期表
  13. Android神器:Xposed框架
  14. 编程序,输出1/3-3/5+5/7-7/9…+19/21的结果
  15. 四轴无人机动力学模型
  16. 企业级云管理平台的架构实现与落地实践、趋势分析
  17. 王者荣耀角色信息在哪个服务器,怎么查询王者荣耀角色在哪个区
  18. [世界杯] 巴西 vs 克罗地亚 1:0
  19. python的pytest模块:pytest命令行详解
  20. 学了编程却写出错误代码?程序运行结果与想象不符?当bug出现时该何去何从,别担心,这篇文章统统告诉你!手把手带你调试代码,让bug原形毕露!

热门文章

  1. P5502 [JSOI2015]最大公约数(gcd性质/min性质/分治)
  2. OI群论:从入门到自闭
  3. Codeforces Round #651 (Div. 2) D
  4. CF1039C Network Safety
  5. Java的学习与java大数运算
  6. [dsu on tree]树上启发式合并总结(算法思想及模板附例题练习)
  7. P4700-[CEOI2011]Traffic【tarjan,dp】
  8. P4983-忘情【wqs二分,斜率优化】
  9. P4774-[NOI2018]屠龙勇士【EXCRT】
  10. USACO2.4のP1522-牛的旅行(Cow Tours)【最短路Flody】