【发布时间】:2015-11-21 02:25:15
【问题描述】:
我有一个 asp.net MVC 应用程序,它有一个控制器操作,它将字符串作为输入并发送合成语音的响应 wav 文件。这是一个简化的例子:
public async Task<ActionResult> Speak(string text)
{
Task<FileContentResult> task = Task.Run(() =>
{
using (var synth = new System.Speech.Synthesis.SpeechSynthesizer())
using (var stream = new MemoryStream())
{
synth.SetOutputToWaveStream(stream);
synth.Speak(text);
var bytes = stream.GetBuffer();
return File(bytes, "audio/x-wav");
}
});
return await task;
}
应用程序(尤其是此操作方法)在 2008 R2 服务器、2012(非 R2)服务器和我的 8.1 开发 PC 上的服务器环境中运行良好。它还在标准的 Azure 2012 R2 虚拟机上运行良好。但是,当我将它部署到三台 2012 R2 服务器(它最终的永久主页)时,操作方法永远不会产生 HTTP 响应——IIS Worker 进程无限期地最大化 CPU 内核之一。使用 Procmon 观看服务器时,事件查看器中没有任何内容,也没有任何内容出现在我身上。我已经通过远程调试附加到该进程,并且synth.Speak(text) 永远不会返回。执行synth.Speak(text) 调用时,我立即在服务器的任务管理器中看到失控的 w3wp.exe 进程。
我的第一个倾向是相信某些进程通常会干扰服务器上的语音合成,但 Windows Narrator 可以正常工作,并且像这样的简单控制台应用程序也可以正常工作:
static void Main(string[] args)
{
var synth = new System.Speech.Synthesis.SpeechSynthesizer();
synth.Speak("hello");
}
所以很明显我不能责怪服务器的语音合成。所以也许我的代码有问题,或者 IIS 配置有什么奇怪的地方?如何使此控制器操作在这些服务器上正常工作?
这是一种测试操作方法的简单方法(只需为路由获取正确的url 值):
<div>
<input type="text" id="txt" autofocus />
<button type="button" id="btn">Speak</button>
</div>
<script>
document.getElementById('btn').addEventListener('click', function () {
var text = document.getElementById('txt').value;
var url = window.location.href + '/speak?text=' + encodeURIComponent(text);
var audio = document.createElement('audio');
var canPlayWavFileInAudioElement = audio.canPlayType('audio/wav');
var bgSound = document.createElement('bgsound');
bgSound.src = url;
var canPlayBgSoundElement = bgSound.getAttribute('src');
if (canPlayWavFileInAudioElement) {
// probably Firefox and Chrome
audio.setAttribute('src', url);
audio.setAttribute('autoplay', '');
document.getElementsByTagName('body')[0].appendChild(audio);
} else if (canPlayBgSoundElement) {
// internet explorer
document.getElementsByTagName('body')[0].appendChild(bgSound);
} else {
alert('This browser probably can\'t play a wav file');
}
});
</script>
【问题讨论】:
-
您是否尝试过使其成为同步操作方法,而不将其包装在任务中?该代码中的线程池可能存在 ASP .NET 不知道的问题。
-
@DmitryS。我不确定我是否可以进行这样的测试...如果未包装
synth.Speak,我会收到运行时异常:InvalidOperationException(此时无法启动异步操作)。我喜欢这种思路,但如果这是 ASP.NET 的线程池问题,为什么它会在这么多其他服务器上工作? -
最新版合成器有
SpeakAsync()方法。不用将代码包装在Task.Run()中,您只需执行await SpeakAsync(text)。 msdn.microsoft.com/en-us/library/… -
也许我在这里遗漏了一些东西 -
SpeakAsync()方法不会返回任务,因此无法等待。 (它返回一个Prompt对象)。 -
你尝试过这里的建议吗:peterluzc.blogspot.ru/2014/01/…?我知道这是关于异常而不是挂起,但仍然可能相关。
标签: c# asp.net-mvc text-to-speech windows-server-2012-r2 speech-synthesis