繁体   English   中英

异步方法中的意外行为

[英]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 TaskCompletionSourceTask属性:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM