Skip to content

Commit 7fd821e

Browse files
ZhaoChaoqunclaude
andcommitted
fix: resolve flush queue starvation and PR review issues in DualEngineASR
- Add isFlushing cancellation flag (lock-protected) to skip stale processAudio blocks in qwenQueue when flush is initiated, preventing 20-30s hangs caused by pending Metal GPU inference blocking the flush - Move qwenHasOutput reset inside qwenQueue.sync in reset() to prevent race condition with in-flight processAudio blocks - Replace fragile force unwrap (unfixedText!) with optional chaining Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1a9699c commit 7fd821e

1 file changed

Lines changed: 33 additions & 9 deletions

File tree

Sources/DualEngineASR.swift

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,23 +42,42 @@ class DualEngineASR: ASREngine {
4242
/// 被 Paraformer 的 recognitionQueue 和 qwenQueue 两个队列读写,
4343
/// 使用 os_unfair_lock 保护以确保线程安全。
4444
private var _qwenHasOutput = false
45-
private var _qwenLock = os_unfair_lock_s()
45+
private var lock = os_unfair_lock_s()
46+
47+
/// flush 进行中标志。设为 true 后,qwenQueue 中排队的 processAudio 块会立即跳过,
48+
/// 避免 flush 块被大量耗时的 Metal GPU 推理阻塞。
49+
private var _isFlushing = false
4650

4751
let needsPunctuation = false
4852
let needsITN = true
4953

5054
/// 线程安全读取 qwenHasOutput
5155
private var qwenHasOutput: Bool {
5256
get {
53-
os_unfair_lock_lock(&_qwenLock)
57+
os_unfair_lock_lock(&lock)
5458
let value = _qwenHasOutput
55-
os_unfair_lock_unlock(&_qwenLock)
59+
os_unfair_lock_unlock(&lock)
5660
return value
5761
}
5862
set {
59-
os_unfair_lock_lock(&_qwenLock)
63+
os_unfair_lock_lock(&lock)
6064
_qwenHasOutput = newValue
61-
os_unfair_lock_unlock(&_qwenLock)
65+
os_unfair_lock_unlock(&lock)
66+
}
67+
}
68+
69+
/// 线程安全读写 isFlushing
70+
private var isFlushing: Bool {
71+
get {
72+
os_unfair_lock_lock(&lock)
73+
let value = _isFlushing
74+
os_unfair_lock_unlock(&lock)
75+
return value
76+
}
77+
set {
78+
os_unfair_lock_lock(&lock)
79+
_isFlushing = newValue
80+
os_unfair_lock_unlock(&lock)
6281
}
6382
}
6483

@@ -85,13 +104,13 @@ class DualEngineASR: ASREngine {
85104

86105
// 2. 同步推送给 QwenASR 流式引擎,产出文本后接管 HUD
87106
qwenQueue.async { [weak self] in
88-
guard let self = self else { return }
107+
guard let self = self, !self.isFlushing else { return }
89108
_ = self.qwenRecognizer.pushAudio(samples: samples, finalize: false)
90109

91110
let stableText = self.qwenRecognizer.getResult()
92111
let unfixedText = self.qwenRecognizer.getUnfixed()
93112

94-
let hasContent = !stableText.isEmpty || (unfixedText != nil && !unfixedText!.isEmpty)
113+
let hasContent = !stableText.isEmpty || !(unfixedText?.isEmpty ?? true)
95114
if hasContent {
96115
if !self.qwenHasOutput {
97116
self.qwenHasOutput = true
@@ -103,6 +122,10 @@ class DualEngineASR: ASREngine {
103122
}
104123

105124
func flush(completion: @escaping (String) -> Void) {
125+
// 先设置 flushing 标志,让 qwenQueue 中排队的 processAudio 块立即跳过,
126+
// 避免 flush 块被大量耗时的 Metal GPU 推理阻塞
127+
isFlushing = true
128+
106129
qwenQueue.async { [weak self] in
107130
guard let self = self else {
108131
DispatchQueue.main.async { completion("") }
@@ -132,10 +155,11 @@ class DualEngineASR: ASREngine {
132155
}
133156

134157
func reset() {
135-
qwenHasOutput = false
136-
paraformerEngine.reset()
137158
qwenQueue.sync {
159+
_qwenHasOutput = false
160+
_isFlushing = false
138161
qwenRecognizer.reset()
139162
}
163+
paraformerEngine.reset()
140164
}
141165
}

0 commit comments

Comments
 (0)