System.Speech.Synthesis在2012 R2上的高CPU挂起 [英] System.Speech.Synthesis hangs with high CPU on 2012 R2

查看:76
本文介绍了System.Speech.Synthesis在2012 R2上的高CPU挂起的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个asp.net MVC应用程序,该应用程序具有控制器操作,该操作将字符串作为输入并发送合成语音的响应wav文件.这是一个简化的示例:

I have an asp.net MVC application that has a controller action that takes a string as input and sends a response wav file of the synthesized speech. Here is a simplified example:

    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 ​​dev PC上的服务器环境中运行良好.它还可以在标准Azure 2012 R2虚拟机上正常运行.但是,当我将其部署到三台2012 R2服务器(最终成为永久宿主)时,该操作方法将永远不会产生HTTP响应-IIS Worker进程会无限期地最大化一个CPU内核.使用Procmon观看服务器时,事件查看器中没有任何内容,也没有任何提示跳到我身上.我已通过远程调试附加到该过程,并且synth.Speak(text)永不返回.当执行synth.Speak(text)调用时,我立即在服务器的任务管理器中看到失控的w3wp.exe进程.

The application (and this action method in particular) is running fine in a server environment on 2008 R2 servers, 2012 (non-R2) servers, and my 8.1 dev PC. It is also running fine on a standard Azure 2012 R2 virtual machine. However, when I deploy it to three 2012 R2 servers (its eventual permanent home), the action method never produces an HTTP response -- the IIS Worker process maxes one of the CPU cores indefinitely. There is nothing in the event viewer and nothing jumps out at me when watching the server with Procmon. I've attached to the process with remote debugging, and the synth.Speak(text) never returns. When the synth.Speak(text) call is executed I immediately see the runaway w3wp.exe process in the server's task manager.

我的第一个倾向是相信服务器上的某些过程通常会干扰语音合成,但是Windows Narrator可以正常工作,并且像这样的简单控制台应用程序也可以正常工作:

My first inclination was to believe some process was interfering with speech synthesis in general on the servers, but the Windows Narrator works correctly, and a simple console app like this also works correctly:

static void Main(string[] args)
{
    var synth = new System.Speech.Synthesis.SpeechSynthesizer();
    synth.Speak("hello");
}

因此,很明显,我一般不能怪服务器的语音合成.因此,也许我的代码有问题,或者IIS配置中有些奇怪?如何使此控制器操作在这些服务器上正常工作?

So obviously I can't blame the server's speech synthesis in general. So maybe there is a problem in my code, or something strange in IIS configuration? How can I make this controller action work correctly on these servers?

这是测试操作方法的简单方法(只需为路由正确获得url值):

This is a simple way to test the action method (just have to get the url value right for the routing):

<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>

推荐答案

我发现我可以在包括Azure VM在内的其他服务器上重现该问题,因此排除了我们特定环境可能出现问题的可能性.

I found that I can reproduce the issue on other servers, including Azure VMs, so I ruled out the possibility of an issue with our particular environment.

此外,我发现,如果我以服务器上的管理员身份并先前登录服务器来运行应用程序池,则可以使代码在2012 R2上正常工作.经过很长的排除权限问题的过程,我认为登录过程中一定有某种东西可以使TTS API调用正常工作. (无论它是什么,我都无法通过procmon跟踪来发现它).因此,幸运的是,通过在IIS中打开应用程序池的高级设置"并将Load User Profile设置为True,ApplicationPoolIdentity可以应用类似的登录魔术.

Also, I found that I could get the code to work fine on 2012 R2 if I ran the application pool under an identity that was an admin on the server and had previously logged into the server. After a very long process of ruling out permissions issues I decided it must be something in the logging in process that occurs that enables the TTS API calls to work correctly. (Whatever it is, I wasn't able to find it digging through procmon traces). So fortunately the ApplicationPoolIdentity can have similar login magic applied by opening "Advanced Settings" for the app pool in IIS and setting Load User Profile to True.

运行应用程序池的标识还需要读取HKU\.Default\Software\Microsoft\Speech的权限,可以通过使用本地服务器作为位置并将IIS APPPOOL\.Net v4.5作为用户名(其中.Net v4.5是应用程序的名称)来授予ApplicationPoolIdentity池).

The identity that runs the app pool also needs permission to read HKU\.Default\Software\Microsoft\Speech which can be granted to ApplicationPoolIdentity by using the local server for the location and IIS APPPOOL\.Net v4.5 for the username (where .Net v4.5 is the name of the application pool).

一旦授予了对reg键的读取权限,并且将应用程序池配置为加载用户配置文件,则上述代码可以正常工作.在MSDN ISO的Azure VM和vanilla 2012 R2上进行了测试.

Once read permission to the reg key is granted, and the app pool is configured to load user profile, the above code works fine. Tested on Azure VMs and vanilla 2012 R2 from MSDN ISOs.

这篇关于System.Speech.Synthesis在2012 R2上的高CPU挂起的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆