利用threading库实现python多线程以多线程音频实时输入为例

利用threading库实现python多线程以多线程音频实时输入为例

threading详解

1. 线程的概念:

线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。

2. threading.thread()的简单使用

import threading
import time
 
def saySorry():
     print("啊吧吧吧啊啊啊")
     time.sleep(1)
if __name__ == "__main__":
     for i in range(5):
     t = threading.Thread(target=saySorry)
     t.start() #启动线程,即让线程开始执行

1.线程定义使用threading.Thread(target=saySorry)定义,线程函数由target指定。
2.线程调用使用start函数进行调用。
3.线程数=主线程数+子线程数,主线程结束于所有的子线程结束后。

3. 线程数查看

import threading
from time import sleep,ctime
 
def sing():
     for i in range(3):
        print("我好无聊...%d"%i)
     sleep(1)
 
def dance():
     for i in range(3):
        print("啊啊啊...%d"%i)
     sleep(1)
 
if __name__ == '__main__':
     print('---开始---:%s'%ctime()) 
     t1 = threading.Thread(target=sing)
     t2 = threading.Thread(target=dance)
     t1.start()
     t2.start()
     while True:
         length = len(threading.enumerate())
         print('当前运行的线程数为:%d'%length)
         if length<=1:
             break
         sleep(0.5)

5. 线程传参

1.使用args 传递参数 threading.Thread(target=sing, args=(10, 100, 100))
2.使用kwargs传递参数 threading.Thread(target=sing, kwargs={“a”: 10, “b”:100, “c”: 100})
3.同时使用 args 和 kwargs 传递参数 threading.Thread(target=sing, args=(10, ), kwargs={“b”: 100,“c”: 100})

6. 线程执行顺序

import socket
import threading
import time
 
def sing():
     for i in range(10):
     print("------------------------------")
     time.sleep(0.5)
    
def dance():
     for i in range(10):
     print("-----")
     time.sleep(0.5)
 
if __name__ == '__main__':
     # 创建两个子线程
     t1 = threading.Thread(target=sing)
     t2 = threading.Thread(target=dance)
     # 启动子线程
     t1.start()
     t2.start()

说明:
从代码和执行结果我们可以看出,多线程程序的执行顺序是不确定的。当执行到sleep语句时,线程将被阻塞(Blocked),到sleep结束后,线程进入就绪(Runnable)状态,等待调度。而线程调度将自行选择一个线程执行。上面的代码中只能保证每个线程都运行完整个run函数,但是线程的启动顺序、run函数中每次循环的执行顺序都不能确定。

7. 线程处理标记threading.Event()

通过threading.Event()可以创建一个事件管理标志,该标志(event)默认为False,event对象主要有四种方法可以调用:

event.wait(timeout=None):调用该方法的线程会被阻塞,如果设置了timeout参数,超时后,线程会停止阻塞继续执行;
event.set():将event的标志设置为True,调用wait方法的所有线程将被唤醒
event.clear():将event的标志设置为False,调用wait方法的所有线程将继续被阻塞
event.isSet():判断event的标志是否为True

8. 线程同步标记.join()

joIn的作用:join所完成的工作就是线程同步,即主线程任务结束之后,进入阻塞状态,一直等待其他的子线程执行结束之后,主线程在终止,

import time
from multiprocessing import Process
import os
def run():
    print("子进程开启")
    time.sleep(2)
    print("子进程结束")


if __name__ == "__main__":
    print("父进程启动")
    p = Process(target=run)
    p.start()
    # p.join()
    print("父进程结束")

# 输出结果
父进程启动
父进程结束
子进程开启
子进程结束
使用join后,输出结果:
父进程启动
子进程开启
子进程结束
父进程结束

join()有参数即等待几秒,不带参数即等待线程结束

实时音频检测分析

1.1库引用

import threading
from array import array
from queue import Queue as queue
import pyaudio

1.2基本参数设置

# 音频段大小
CHUNK_SIZE = 1024
# 最小声音大小,单位:?
MIN_VOLUME = 2000
# 当待处理音频段过多即丢弃实时音频段
# 这里将队列最大处理段置为10个待处理音频段
BUF_MAX_SIZE = CHUNK_SIZE * 10
# 定义线程终止标志
stopped = threading.Event()
# 定义待处理音频队列
q = queue(int(round(BUF_MAX_SIZE / CHUNK_SIZE)))

1.3主函数

def main():
	#耳朵线程,传入参数为(标志,队列)
    listen_t = threading.Thread(target=listen, args=(stopped, q))
    #启动耳朵线程
    listen_t.start()
    #定义记录线程,同上
    record_t = threading.Thread(target=record, args=(stopped, q))
    record_t.start()    
    try:
        while True:
        	#阻塞主线程等待耳朵线程0.1s
            listen_t.join(0.1)
            #阻塞主线程等待耳朵线程0.1s
            record_t.join(0.1)
    #越界退出
    except KeyboardInterrupt:
    	#唤醒阻塞标记
        stopped.set()
    #等待耳朵线程以及记录线程结束
    listen_t.join()
    record_t.join()

1.4记录线程

	def record(stopped, q):
    while True:
    	#若阻塞进程被唤醒结束此线程
        if stopped.wait(timeout=0):
            break
        #弹出队头
        chunk = q.get()
        #音量测试
        vol = max(chunk)
        if vol >= MIN_VOLUME:
            #插入有声信息帧队列
            print("O"),
        else:
        	#插入无声信息帧队列
            print("-"),

1.5耳朵线程

def listen(stopped, q):
	#使用pyaudio进行音频录制,具体录制函数见下一篇博客
    stream = pyaudio.PyAudio().open(
        format=pyaudio.paInt16,
        channels=2,
        rate=44100,
        input=True,
        frames_per_buffer=1024,
    )
    while True:
    	#若阻塞标志被唤醒则结束此线程
        if stopped.wait(timeout=0):
            break
        try:
        	#将此0.1s语音入队
            q.put(array('h', stream.read(CHUNK_SIZE)))
        #待处理队列满则丢弃语音帧    
        except q.full():
            pass  # discard

实时音频检测代码

import threading
from array import array
from queue import Queue as queue
import pyaudio
CHUNK_SIZE = 1024
MIN_VOLUME = 2000
BUF_MAX_SIZE = CHUNK_SIZE * 10
stopped = threading.Event()
q = queue(int(round(BUF_MAX_SIZE / CHUNK_SIZE)))
def main():
    listen_t = threading.Thread(target=listen, args=(stopped, q))
    listen_t.start()
    record_t = threading.Thread(target=record, args=(stopped, q))
    record_t.start()    
    try:
        while True:
            listen_t.join(0.1)
            record_t.join(0.1)
    except KeyboardInterrupt:
        stopped.set()
    listen_t.join()
    record_t.join()
def record(stopped, q):
    while True:
        if stopped.wait(timeout=0):
            break
        chunk = q.get()
        vol = max(chunk)
        if vol >= MIN_VOLUME:
            # TODO: write to file
            print("O"),
        else:
            print("-"),
def listen(stopped, q):
    stream = pyaudio.PyAudio().open(
        format=pyaudio.paInt16,
        channels=2,
        rate=44100,
        input=True,
        frames_per_buffer=1024,
    )
    while True:
        if stopped.wait(timeout=0):
            break
        try:
            q.put(array('h', stream.read(CHUNK_SIZE)))
        except q.full():
            pass  # discard
if __name__ == '__main__':
    main()

引用地址

https://oomake.com/question/5468537
https://blog.csdn.net/weixin_38848437/article/details/123736285

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值