在Xamarin中实现Azure TTS方法的互斥执行方案咨询
Xamarin中Azure TTS的互斥调用解决方案
问题背景
在Xamarin应用中集成Azure文本转语音(TTS)服务时,两个由定时器触发的方法(M1、M2)会调用TTS接口,需要确保同一时间只有一个TTS合成任务在执行,但使用Lock、Monitor、SemaphoreSlim等同步方式未解决并发问题。
问题根源
- TTS服务类的
Speak方法使用async void,调用方无法等待其执行完成,导致同步机制无法生效。 - 定时器的
Elapsed事件在独立线程触发,同步对象未在正确的异步上下文生效。
解决方案
1. 修改TTS服务类,引入异步安全的同步机制
在TextToSpeech类中使用SemaphoreSlim实现异步互斥,同时将Speak方法改为async Task以便调用方等待:
using Microsoft.CognitiveServices.Speech; namespace PorjectB1.Model { public class TextToSpeech { static private string speechKey { get; set; } static private string speechRegion { get; set; } // 初始化信号量,仅允许1个并发任务执行 private readonly SemaphoreSlim _speechSemaphore = new SemaphoreSlim(1, 1); public TextToSpeech() { speechKey = "***"; speechRegion = "***"; } static void OutputSpeechSynthesisResult(SpeechSynthesisResult speechSynthesisResult, string text) { switch (speechSynthesisResult.Reason) { case ResultReason.SynthesizingAudioCompleted: //Log Something break; case ResultReason.Canceled: //Log Something break; default: //Log Something break; } } public async Task Speak(string text) { // 异步等待信号量,获取执行权限 await _speechSemaphore.WaitAsync(); try { var speechConfig = SpeechConfig.FromSubscription(speechKey, speechRegion); using (var speechSynthesizer = new SpeechSynthesizer(speechConfig)) { var speechSynthesisResult = await speechSynthesizer.SpeakTextAsync(text); OutputSpeechSynthesisResult(speechSynthesisResult, text); } } finally { // 释放信号量,允许下一个任务执行 _speechSemaphore.Release(); } } } }
2. 修改主页面代码,确保等待TTS任务完成
将主页面中的Speak方法改为异步方法,并在M1、M2中等待其执行完成,适配定时器线程的上下文:
namespace PorjectB1.Controller { public partial class MainPage : ContentPage { private System.Timers.Timer m1Timer; private System.Timers.Timer m2Timer; static Model.TextToSpeech ttsService = new Model.TextToSpeech(); public MainPage() { InitializeComponent(); m1Timer= new System.Timers.Timer(15000); m1Timer.Elapsed += OnM1TimerElapsed; m1Timer.AutoReset = true; m1Timer.Enabled = true; m2Timer = new System.Timers.Timer(60000); m2Timer.Elapsed += OnM2Elapsed; m2Timer.AutoReset = true; m2Timer.Enabled = true; } private async void OnM1TimerElapsed(object sender, ElapsedEventArgs e) { await M1(); } private async void OnM2Elapsed(object sender, ElapsedEventArgs e) { await M2(); } private async Task M1() { string SpeechText=string.Empty; //Do Something... await Speak(SpeechText); } private async Task M2() { string SpeechText=string.Empty; //Do Something... await Speak(SpeechText); } private async Task Speak(string text) { await ttsService.Speak(text); } } }
关键说明
SemaphoreSlim.WaitAsync():异步等待信号量,不会阻塞线程,完美适配异步场景下的并发控制。- 替换
async void为async Task:让调用方能够等待TTS任务执行完成,确保同步机制真正生效。 finally块释放信号量:保证即使TTS任务抛出异常,信号量也能被正确释放,避免出现死锁情况。
内容的提问来源于stack exchange,提问作者Kadir Beskardes
相关产品推荐
相关产品推荐

