python thread start_Python threading.thread.start()不会将控制权返回给主线程

I'm trying to a program that executes a piece of code in such a way that the user can stop its execution at any time without stopping the main program. I thought I could do this using threading.Thread, but then I ran the following code in IDLE (Python 3.3):

from threading import *

import math

def f():

eval("math.factorial(1000000000)")

t = Thread(target = f)

t.start()

The last line doesn't return: I eventually restarted the shell. Is this a consequence of the Global Interpreter Lock, or am I doing something wrong? I didn't see anything specific to this problem in the threading documentation (http://docs.python.org/3/library/threading.html)

I tried to do the same thing using a process:

from multiprocessing import *

import math

def f():

eval("math.factorial(1000000000)")

p = Process(target = f)

p.start()

p.is_alive()

The last line returns False, even though I ran it only a few seconds after I started the process! Based on my processor usage, I am forced to conclude that the process never started in the first place. Can somebody please explain what I am doing wrong here?

解决方案Thread.start() never returns! Could this have something to do with the C implementation of the math library?

As @eryksun pointed out in the comment: math.factorial() is implemented as a C function that doesn't release GIL so no other Python code may run until it returns.

Note: multiprocessing version should work as is: each Python process has its own GIL.

factorial(1000000000) has hundreds millions of digits. Try import time; time.sleep(10) as dummy calculation instead.

If you have issues with multithreaded code in IDLE then try the same code from the command line, to make sure that the error persists.

If p.is_alive() returns False after p.start() is already called then it might mean that there is an error in f() function e.g., MemoryError.

On my machine, p.is_alive() returns True and one of cpus is at 100% if I paste your code from the question into Python shell.

Unrelated: remove wildcard imports such as from multiprocessing import *. They may shadow other names in your code so that you can't be sure what a given name means e.g., threading could define eval function (it doesn't but it could) with a similar but different semantics that might break your code silently.

I want my program to be able to handle ridiculous inputs from the user gracefully

If you pass user input directly to eval() then the user can do anything.

Is there any way to get a process to print, say, an error message without constructing a pipe or other similar structure?

It is an ordinary Python code:

print(message) # works

The difference is that if several processes run print() then the output might be garbled. You could use a lock to synchronize print() calls.

为什么以下代码进入了sounddevice.RawInputStream的回调函数 from vosk import Model, KaldiRecognizer import sounddevice as sd import queue import threading import pystray from PIL import Image sd.RawInputStream(device=1) class VoiceWakeup: def __init__(self, wake_word="你好大力"): self.wake_word = wake_word self.model = Model(r"vosk-model-small-cn-0.22") # 需下载中文模型 # self.sample_rate = 16000 self.sample_rate = 44100 self.audio_queue = queue.Queue() self.is_listening = False def _audio_callback(self, indata, frames, time, status): print('indata') print(indata) self.audio_queue.put(bytes(indata)) def _process_audio(self): rec = KaldiRecognizer(self.model, self.sample_rate) while self.is_listening: data = self.audio_queue.get() if rec.AcceptWaveform(data): result = rec.Result() if self.wake_word in result: return True # 触发唤醒事件 return False def start_listen(self): self.is_listening = True print('enter start_listen') with sd.RawInputStream( samplerate=self.sample_rate, blocksize=4096, dtype="int16", channels=1, callback=self._audio_callback) as stream: threading.Thread(target=self._process_audio).start() class TrayApp: def __init__(self): # 初始化语音唤醒模块 self.voice = VoiceWakeup(wake_word="启动助手") # 创建托盘图标 self.icon = pystray.Icon( name="VoiceTray", icon=Image.new("RGB", (64, 64), "blue"), menu=pystray.Menu( pystray.MenuItem("开启监听", self.start_listen), pystray.MenuItem("退出", self.on_exit) ) ) def on_wake(self): print(">>> 检测到唤醒词!") # 此处可扩展:显示通知/打开主界面等 self.icon.notify("语音指令已接收", "系统提示") def start_listen(self, icon, item): threading.Thread(target=self._listen_thread,daemon=True).start() def _listen_thread(self): if self.voice.start_listen(): self.on_wake() def on_exit(self, icon, item): self.voice.is_listening = False icon.stop() if __name__ == "__main__": TrayApp().icon.run() # import sounddevice as sd # # # 必须明确指定dtype(如设备原生格式为int16) # dtype = 'int16' # 常见设备原生格式 # samplerate = 44100 # channels = 1 # # # def raw_callback(indata, frames: int, time, status): # """indata已经是原始二进制数据转换后的numpy数组""" # # 此处直接处理原始音频数据(例如实时传输) # print(f"收到原始数据块: {indata}") # # # # 关键参数必须准确匹配设备能力 # with sd.RawInputStream( # callback=raw_callback, # dtype=dtype, # samplerate=samplerate, # channels=channels, # blocksize=4096 # 必须明确设置且为2的幂 # ) as stream: # input("按Enter停止采集...")
05-11
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值