[英]Unexpected behavior in async method
我目前正在尝试使用aync方法来执行某些意外/不必要的行为。 异步方法是RecognizeAsync
。 我无法等待此方法,因为它返回void。 发生的情况是,将首先调用ProcessAudio
方法,并且该方法似乎可以运行完成,但是该网页从不返回我的“ Contact”视图,因为它应该出现或出现错误。 方法运行完成后,我的处理程序中的断点开始出现。 如果我让它一直进行到完成,则不会发生任何重定向-在chrome调试器的“网络”标签中,“状态”将保持标记为待处理状态,并仅挂在那里。 我认为我的问题是由异步问题引起的,但一直无法确定它到底是什么。
感谢所有帮助。
[HttpPost]
public async Task<ActionResult> ProcessAudio()
{
SpeechRecognitionEngine speechEngine = new SpeechRecognitionEngine();
speechEngine.SetInputToWaveFile(Server.MapPath("~/Content/AudioAssets/speechSample.wav"));
var grammar = new DictationGrammar();
speechEngine.LoadGrammar(grammar);
speechEngine.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(SpeechRecognizedHandler);
speechEngine.SpeechHypothesized += new EventHandler<SpeechHypothesizedEventArgs>(SpeechHypothesizedHandler);
speechEngine.RecognizeAsync(RecognizeMode.Multiple);
return View("Contact", vm); //first breakpoint hit occurs on this line
//but it doesnt seem to be executed?
}
private void SpeechRecognizedHandler(object sender, EventArgs e)
{
//do some work
//3rd breakpoint is hit here
}
private void SpeechHypothesizedHandler(object sender, EventArgs e)
{
//do some different work
//2nd breakpoint is hit here
}
更新:根据建议,我将代码更改为(在ProcessAudio中):
using (speechEngine)
{
speechEngine.SetInputToWaveFile(Server.MapPath("~/Content/AudioAssets/speechSample.wav"));
var grammar = new DictationGrammar();
speechEngine.LoadGrammar(grammar);
speechEngine.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(SpeechRecognizedHandler);
speechEngine.SpeechHypothesized += new EventHandler<SpeechHypothesizedEventArgs>(SpeechHypothesizedHandler);
var tcsRecognized = new TaskCompletionSource<EventArgs>();
speechEngine.RecognizeCompleted += (sender, eventArgs) => tcsRecognized.SetResult(eventArgs);
speechEngine.RecognizeAsync(RecognizeMode.Multiple);
try
{
var eventArgsRecognized = await tcsRecognized.Task;
}
catch(Exception e)
{
throw (e);
}
}
这会导致某些错误的行为:在处理程序完成触发之后,现在将return View("Contact",vm)
断点,但是仍然不会发生重定向。 我从不直接进入我的联系页面。 我就像以前一样无限期地停留在原始页面上。
你太早了 到return View
行时,语音引擎甚至可能还没有启动。
您需要等待,直到语音引擎触发了最终事件。 最好的方法是将基于事件的异步转换为基于TAP的异步 。
这可以通过使用TaskCompletionSource<T>
来实现。
让我们来处理(我相信)应该是火灾发生后的最后一个事件speechEngine.RecognizeAsync
被调用,即SpeechRecognized
。 我假设这是语音引擎计算出最终结果时触发的事件。
因此,首先:
var tcs = new TaskCompletionSource<EventArgs>();
现在,使用内联lambda样式方法声明,将其连接起来以在激发SpeechRecognized
时完成:
speechEngine.SpeechRecognized += (sender, eventArgs) => tcs.SetResult(eventArgs);
(...等等。如果没有语音被识别该怎么办?我们还需要连接SpeechRecognitionRejected
事件并为此类事件定义一个自定义Exception子类...在这里,我将其称为RecognitionFailedException
。现在我们正在捕获识别过程的所有可能结果,因此我们希望TaskCompletionSource
在所有结果中都能完成。)
speechEngine.SpeechRecognitionRejected += (sender, eventArgs) =>
tcs.SetException(new RecognitionFailedException());
然后
speechEngine.RecognizeAsync(RecognizeMode.Multiple);
现在,我们可以await
TaskCompletionSource
的Task
属性:
try
{
var eventArgs = await tcs.Task;
}
catch(RecognitionFailedException ex)
{
//this would signal that nothing was recognized
}
对作为任务结果的EventArgs进行一些处理,然后将可行的结果返回给客户端。
在执行此操作的过程中,您正在创建IDisposable
实例,这些实例需要正确处理。
所以:
using(SpeechRecognitionEngine speechEngine = new SpeechRecognitionEngine())
{
//use the speechEngine with TaskCompletionSource
//wait until it's finished
try
{
var eventArgs = await tcs.Task;
}
catch(RecognitionFailedException ex)
{
//this would signal that nothing was recognized
}
} //dispose
如果有人好奇-我通过以下操作解决了我的问题:
我更改为使用Recognize()
而不是RecognizeAsync(..)
,这是由于尝试在“页面生命周期的无效时间”执行异步事件而导致InvalidOperationException
。 为了克服这个问题,我将操作包裹在一个线程中,并在运行后直接将其加入主线程。 代码如下:
using (speechEngine)
{
var t = new Thread(() =>
{
speechEngine.SetInputToWaveFile(@"C:\AudioAssets\speechSample.wav");
speechEngine.LoadGrammar(dictationGrammar);
speechEngine.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(SpeechRecognizedHandler);
speechEngine.SpeechHypothesized += new EventHandler<SpeechHypothesizedEventArgs>(SpeechHypothesizedHandler);
speechEngine.Recognize();
});
t.Start();
t.Join();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.