python中的多线程编程与暂停、播放音频的结合
先给两个原文链接:
https://blog.csdn.net/u013755307/article/details/19913655
https://www.cnblogs.com/scolia/p/6132950.html
播放wav音频的原代码:
#引入库
import pyaudio
import wave
import sys #定义数据流块
chunk = 1024 #只读方式打开wav文件
f = wave.open(r"../resource/3.wav","rb") p = pyaudio.PyAudio() #打开数据流
stream = p.open(format = p.get_format_from_width(f.getsampwidth()),
channels = f.getnchannels(),
rate = f.getframerate(),
output = True) #读取数据
data = f.readframes(chunk) #播放
while data !="":
stream.write(data)
data = f.readframes(chunk) #停止数据流
stream.stop_stream()
stream.close() #关闭 PyAudio
p.terminate()
对其进行封装之后的代码:
#-*-coding:utf-8-*- #引入库
import pyaudio
import wave
import sys # 定义数据流块
CHUNK = 1024 # if len(sys.argv) < 2:
# print("Plays a wave file.\n\nUsage: %s filename.wav" % sys.argv[0])
# sys.exit(-1)
class playWavAudio():
def __init__(self):
#只读方式打开wav文件
self.wf = wave.open(r'../resource/3.wav', 'rb') #(sys.argv[1], 'rb')
def play(self): p = pyaudio.PyAudio() #创建一个播放器 # 打开数据流
stream = p.open(format=p.get_format_from_width(self.wf.getsampwidth()),
channels=self.wf.getnchannels(),
rate=self.wf.getframerate(),
output=True) # 读取数据
data = self.wf.readframes(CHUNK) # 播放
while data != '':
stream.write(data)
data = self.wf.readframes(CHUNK) # 停止数据流
stream.stop_stream()
stream.close() # 关闭 PyAudio
p.terminate() if __name__ == "__main__":
aaa = playWavAudio()
aaa.play()
多线程(暂停,恢复,停止)的代码:
import threading
import time class Job(threading.Thread): def __init__(self, *args, **kwargs):
super(Job, self).__init__(*args, **kwargs)
self.__flag = threading.Event() # 用于暂停线程的标识
self.__flag.set() # 设置为True
self.__running = threading.Event() # 用于停止线程的标识
self.__running.set() # 将running设置为True def run(self):
while self.__running.isSet():
self.__flag.wait() # 为True时立即返回, 为False时阻塞直到内部的标识位为True后返回
print(time.time())
time.sleep(1)
# print("sleep 1s")
def pause(self):
self.__flag.clear() # 设置为False, 让线程阻塞
print("pause")
def resume(self):
self.__flag.set() # 设置为True, 让线程停止阻塞
print("resume")
def stop(self):
# self.__flag.set() # 将线程从暂停状态恢复, 如果已经暂停的话(要是停止的话我就直接让他停止了,干嘛还要执行这一句语句啊,把这句注释了之后就没有滞后现象了。)
self.__running.clear() # 设置为False
print("停止!")
if __name__ == "__main__":
a = Job()
a.start()
time.sleep(3)
a.pause()
time.sleep(6)
a.resume()
time.sleep(3)
a.pause()
time.sleep(2)
a.stop()
原文解释:
我们都知道python中可以是threading模块实现多线程, 但是模块并没有提供暂停, 恢复和停止线程的方法, 一旦线程对象调用start方法后, 只能等到对应的方法函数运行完毕. 也就是说一旦start后, 线程就属于失控状态. 不过, 我们可以自己实现这些. 一般的方法就是循环地判断一个标志位, 一旦标志位到达到预定的值, 就退出循环. 这样就能做到退出线程了. 但暂停和恢复线程就有点难了, 我一直也不清除有什么好的方法, 直到我看到threading中Event对象的wait方法的描述时. 复制代码
wait([timeout]) Block until the internal flag is true. If the internal flag is true on entry, return immediately. Otherwise, block until another thread calls set() to set the flag to true, or until the optional timeout occurs. 阻塞, 直到内部的标志位为True时. 如果在内部的标志位在进入时为True时, 立即返回. 否则, 阻塞直到其他线程调用set()方法将标准位设为True, 或者到达了可选的timeout时间. When the timeout argument is present and not None, it should be a floating point number specifying a timeout for the operation in seconds (or fractions thereof). This method returns the internal flag on exit, so it will always return True except if a timeout is given and the operation times out. 当给定了timeout参数且不为None, 它应该是一个浮点数,以秒为单位指定操作的超时(或是分数)。 此方法在退出时返回内部标志,因此除非给定了超时且操作超时,否则它将始终返回True。 Changed in version 2.7: Previously, the method always returned None. 2.7版本以前, 这个方法总会返回None.
复制代码 利用wait的阻塞机制, 就能够实现暂停和恢复了, 再配合循环判断标识位, 就能实现退出了, 下面是代码示例: 这完成了暂停, 恢复和停止的功能. 但是这里有一个缺点: 无论是暂停还是停止, 都不是瞬时的, 必须等待run函数内部的运行到达标志位判断时才有效. 也就是说操作会滞后一次. 但是这有时也不一定是坏事. 如果run函数中涉及了文件操作或数据库操作等, 完整地运行一次后再退出, 反而能够执行剩余的资源释放操作的代码(例如各种close). 不会出现程序的文件操作符超出上限, 数据库连接未释放等尴尬的情况.
原文解析
这里我修改了原作者的一个地方,就是把self.__flag.set()这一句删掉了,因为你要是想直接停止线程的话就不需要以后再执行其他操作了。删了这一句之后原作者所说的滞后现象就没了,原因未知。
将播放音频的代码和线程控制的代码整合后(只播放一次的):
from threading import *
import time
from playsound import playsound
import pyaudio
import wave
# 定义数据流块
CHUNK = 1024
class MyThread(Thread):
def init(self,filename):
self.wf = wave.open(filename, 'rb') # (sys.argv[1], 'rb')
self.p = pyaudio.PyAudio() # 创建一个播放器
# def init(self,filename):
# 打开数据流
self.stream = self.p.open(format=self.p.get_format_from_width(self.wf.getsampwidth()),
channels=self.wf.getnchannels(),
rate=self.wf.getframerate(),
output=True)
# 读取数据
self.data = self.wf.readframes(CHUNK) self.__flag = Event() # 用于暂停线程的标识
self.__flag.set()
self.ifdo = True; def run (self): while self.ifdo and self.data != '' :
self.__flag.wait()
print('I am running...')
# time.sleep(2) # 播放
self.stream.write(self.data)
self.data = self.wf.readframes(CHUNK)
# self.data = ''
def pause(self):
self.__flag.clear() # 设置为False, 让线程阻塞
print("pause") def resume(self):
self.__flag.set() # 设置为True, 让线程停止阻塞
print("resume")
def stop (self):
print('I am stopping it...')
self.ifdo = False
# def restart(self):
# self.ifdo if __name__ == "__main__":
tr = MyThread()
tr.init("c2.wav")
# tr.setDaemon(True)
tr.start()
print('\nI will pause it...')
time.sleep(2)
tr.pause()
print("i will resume it...")
time.sleep(2)
tr.resume()
print("i will stop it...")
time.sleep(2)
tr.stop()
# time.sleep(1)
# tr.stop()
#
下面是循环播放版本的:
from threading import *
import time
from playsound import playsound
import pyaudio
import wave
# 定义数据流块
CHUNK = 1024
class MyMusic(Thread):
def init(self,filename):
self.filename = filename
self.wf = wave.open(filename, 'rb') # (sys.argv[1], 'rb')
self.p = pyaudio.PyAudio() # 创建一个播放器
# def init(self,filename):
# 打开数据流
self.stream = self.p.open(format=self.p.get_format_from_width(self.wf.getsampwidth()),
channels=self.wf.getnchannels(),
rate=self.wf.getframerate(),
output=True)
# 读取数据
self.data = self.wf.readframes(CHUNK) self.__flag = Event() # 用于暂停线程的标识
self.__flag.set()
self.ifdo = True; def run (self): while self.ifdo :
while len(self.data) > 5:
self.__flag.wait()
print('I am running...')
# time.sleep(2) # 播放
self.stream.write(self.data)
self.data = self.wf.readframes(CHUNK)
self.wf = wave.open(self.filename, 'rb')
self.data = self.wf.readframes(CHUNK)
# self.data = ''
def pause(self):
self.__flag.clear() # 设置为False, 让线程阻塞
print("pause") def resume(self):
self.__flag.set() # 设置为True, 让线程停止阻塞
print("resume")
def stop (self):
print('I am stopping it...')
self.ifdo = False
# def restart(self):
# self.ifdo if __name__ == "__main__":
tr = MyMusic()
tr.init("../resource/2.wav")
# tr.setDaemon(True)
tr.start()
print('\nI will pause it...')
time.sleep(2)
# tr.pause()
print("i will resume it...")
time.sleep(2)
tr.resume()
print("i will stop it...")
time.sleep(2)
# tr.stop()
# time.sleep(1)
# tr.stop()
# tr.join()
python中的多线程编程与暂停、播放音频的结合的更多相关文章
- Python中的多线程编程,线程安全与锁(二)
在我的上篇博文Python中的多线程编程,线程安全与锁(一)中,我们熟悉了多线程编程与线程安全相关重要概念, Threading.Lock实现互斥锁的简单示例,两种死锁(迭代死锁和互相等待死锁)情况及 ...
- Python中的多线程编程,线程安全与锁(一)
1. 多线程编程与线程安全相关重要概念 在我的上篇博文 聊聊Python中的GIL 中,我们熟悉了几个特别重要的概念:GIL,线程,进程, 线程安全,原子操作. 以下是简单回顾,详细介绍请直接看聊聊P ...
- Python中的多线程编程
前言: 线程是操作系统能够进行运算调度的最小单位(程序执行流的最小单元) 它被包含在进程之中,是进程中的实际运作单位 一个进程中可以并发多个线程每条线程并行执行不同的任务 (线程是进程中的一个实体,是 ...
- Python中的并发编程
简介 我们将一个正在运行的程序称为进程.每个进程都有它自己的系统状态,包含内存状态.打开文件列表.追踪指令执行情况的程序指针以及一个保存局部变量的调用栈.通常情况下,一个进程依照一个单序列控制流顺序执 ...
- python多进程与多线程编程
进程(process)和线程(thread)是非常抽象的概念.多线程与多进程编程对于代码的并发执行,提升代码运行效率和缩短运行时间至关重要.下面介绍一下python的multiprocess和thre ...
- Python多进程与多线程编程及GIL详解
介绍如何使用python的multiprocess和threading模块进行多线程和多进程编程. Python的多进程编程与multiprocess模块 python的多进程编程主要依靠multip ...
- Python中的并行编程速度
这里主要想记录下今天碰到的一个小知识点:Python中的并行编程速率如何? 我想把AutoTool做一个并行化改造,主要目的当然是想提高多任务的执行速度.第一反应就是想到用多线程执行不同模块任务,但是 ...
- python中的多线程【转】
转载自: http://c4fun.cn/blog/2014/05/06/python-threading/ python中关于多线程的操作可以使用thread和threading模块来实现,其中th ...
- Python 中的 TK编程
可爱的 Python:Python 中的 TK编程 http://www.ibm.com/developerworks/cn/linux/sdk/python/charm-12/ python che ...
随机推荐
- webService服务简单实现
首先写一个简单的webservice服务 package com.service.impl; import java.util.Date; import javax.jws.WebService; i ...
- 无法启动此程序,因为计算机中丢失api-ms-win-crt-runtime-l1-1-0.dll已解决
问题 : 无法启动此程序,因为计算机中丢失api-ms-win-crt-runtime-l1-1-0.dll 解决 1, 首先把C:\Windows\SysWOW64\的api-ms-win-crt- ...
- 11-MySQL-Ubuntu-数据表中数据的删除(四)
数据的删除(delete) (1)物理删除(不可逆,公司不会采取这种方法,如现在一般不会出现注销,数据具有无限价值) 删除整张表的数据!!! delete from 表名; 删除部分给定条件的数据: ...
- 基于第三方开源库的OPC服务器开发指南(1)——OPC与DCOM
事儿太多,好多事情并不以我的意志为转移,原想沉下心好好研究.学习图像识别,继续丰富我的机器视觉库,并继续<机器视觉及图像处理系列>博文的更新,但计划没有变化快,好多项目要完成,只好耽搁下来 ...
- jquery.js和jquery.min.js的区别和springboot整合echarts.min.js
1.区别:jquery官网提供2种jQuery的下载,一种是jquery.js另一种是jquery.min.js文件名不一定完全相同,但通常情况下:jquery.js是完整的未压缩的jQuery库,文 ...
- JS事件 鼠标移开事件(onmouseout)鼠标移开事件,当鼠标移开当前对象时,执行onmouseout调用的程序。
鼠标移开事件(onmouseout) 鼠标移开事件,当鼠标移开当前对象时,执行onmouseout调用的程序. 当把鼠标移动到"登录"按钮上,然后再移开时,触发onmouseout ...
- 详解redis服务
http://mp.weixin.qq.com/s?__biz=MzIyMDA1MzgyNw==&mid=2651968327&idx=1&sn=6e6cb01d334d7ae ...
- javascript 的学习笔记(第一天)
1.==与=== == 先转换类型,再比较 === 直接比较 2.parseInt 把字符串转成整数 parsefloat 把字符串转成小数 3. 变量的作用域:变量起作用的范围 局部变量: ...
- [JZOJ6257] 【省选模拟8.9】修路
题目 题目大意 有一堆点,每个点都有其权值\(c_i\). 每次插入边\((u,v)\),\(u\)和\(1\)连通,\(v\)和\(1\)不连通.最后保证形成一棵树. 每次插入的时候询问\(1\)到 ...
- PHP跨服务器提交数据
关于类似的问题,百度上一搜一大堆,这只是我自己实际用过的两个方法,不多BB直接上代码 1.第一种: 2.第二种 可以随意切换POST和GET提交方式