【问题标题】:completion port thread is leaking when client terminates the connection当客户端终止连接时,完成端口线程正在泄漏
【发布时间】:2016-05-03 07:45:43
【问题描述】:

我有一个 ASP.NET WebApi 自托管应用程序。 HttpSelfHostConfiguration 配置如下

HttpSelfHostConfiguration config = new HttpSelfHostConfiguration("http://0.0.0.0:54781")
{
    TransferMode = TransferMode.StreamedResponse,
    MaxConcurrentRequests = 1000,
    SendTimeout = TimeSpan.FromMinutes(60),
};

config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "{controller}",
    defaults: new { @controller = "Default" }
);

HttpSelfHostServer server = new HttpSelfHostServer(config);
server.OpenAsync().Wait();

for (;;)
{
    int workerThreads, completionPortThreads;
    ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
    Console.WriteLine("Available Completion Port Threads = {0};", completionPortThreads);
    Console.Out.Flush();
    Thread.Sleep(2000);
}

有一个动作接受如下 HTTP GET 请求

public class DefaultController : ApiController
{
    public HttpResponseMessage GET()
    {
        Console.WriteLine("Receive HTTP GET request");
        Func<Stream, HttpContent, TransportContext, Task> func = (stream, httpContent, transportContext) =>
        {
            return Monitor(httpContent, stream);
        };


        HttpResponseMessage response = Request.CreateResponse();

        response.StatusCode = HttpStatusCode.OK;
        response.Content = new PushStreamContent(func, new MediaTypeHeaderValue("text/plain"));
        return response;
    }

    async Task Monitor(HttpContent httpContent, Stream stream)
    {
        try
        {
            using (StreamWriter sw = new StreamWriter(stream, new UTF8Encoding(false)))
            {
                for (;;)
                {
                    sw.WriteLine(Guid.NewGuid().ToString());
                    sw.Flush();

                    await Task.Delay(1000);
                }
            }
        }
        catch (CommunicationException ce)
        {
            HttpListenerException ex = ce.InnerException as HttpListenerException;
            if (ex != null)
            {
                Console.WriteLine("HttpListenerException occurs, error code = {0}", ex.ErrorCode);
            }
            else
            {
                Console.WriteLine("{0} occurs : {1}", ce.GetType().Name, ce.Message);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("{0} occurs : {1}", ex.GetType().Name, ex.Message);
        }
        finally
        {
            stream.Close();
            stream.Dispose();
            httpContent.Dispose();
            Console.WriteLine("Dispose");
        }
    }
}

打开网址http://127.0.0.1:54781/,我看到了渐进式响应。

但是如果客户端在服务器发送响应时终止连接,完成端口线程被占用并且永远不会释放。

它可以通过耗尽完成端口线程池来关闭应用程序。

【问题讨论】:

    标签: asp.net-web-api2 system.net httplistenerrequest pushstreamcontent


    【解决方案1】:

    改成OWIN自托管后,这个问题就消失了。这似乎是System.Web.Http.SelfHost 中的一个错误

    这里是更新的代码:

    class Program
    {
    
        static void Main(string[] args)
        {
            var server = WebApp.Start<Startup>(url: "http://*:54781");
    
    
            for (;;)
            {
                int workerThreads, completionPortThreads;
                ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
                Console.WriteLine("Worker Threads = {0}; Available Completion Port Threads = {1};", workerThreads, completionPortThreads);
                Console.Out.Flush();
                Thread.Sleep(2000);
            }
        }
    }
    
    public class Startup
    {
        // This code configures Web API. The Startup class is specified as a type
        // parameter in the WebApp.Start method.
        public void Configuration(IAppBuilder appBuilder)
        {
            // Configure Web API for self-host. 
            HttpConfiguration config = new HttpConfiguration();
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "{controller}",
                defaults: new { @controller = "Default" }
            );
    
            appBuilder.UseWebApi(config);
        }
    }
    

    【讨论】:

      【解决方案2】:

      对于其他来这篇文章的人来说,System.Web.Http.SelfHost 中存在类似的问题,默认情况下使用 CPU Cores * 100 个线程,这与默认的 ThreadPool 限制相同,因为 Mono 预先创建了所有线程,因此以死锁结尾。

      解决此问题的最简单方法是将MONO_THREADS_PER_CPU 环境变量设置为大于1 的值,或者在运行Mono 应用程序时使用--server 标志。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-10-28
        • 1970-01-01
        • 1970-01-01
        • 2018-04-29
        • 2021-10-21
        • 1970-01-01
        • 2011-08-22
        • 1970-01-01
        相关资源
        最近更新 更多