Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
我可以告诉.NET GC不要处理一些线程吗? 我正在研究重写一个相对较小的服务从C++到C语言的可能性。该服务有两个主要功能: 偶尔执行一次HTTP请求。它们涉及到一些高级任务,如JSON编码/解码、BASE64编码/解码和HTTP请求本身,其中C++不是很棒的;李> 执行许多实时的、与音频相关的任务,这些任务都有严格的截止日期,而C#并不可怕_C#_.net_Multithreading_Garbage Collection - Fatal编程技术网

我可以告诉.NET GC不要处理一些线程吗? 我正在研究重写一个相对较小的服务从C++到C语言的可能性。该服务有两个主要功能: 偶尔执行一次HTTP请求。它们涉及到一些高级任务,如JSON编码/解码、BASE64编码/解码和HTTP请求本身,其中C++不是很棒的;李> 执行许多实时的、与音频相关的任务,这些任务都有严格的截止日期,而C#并不可怕

我可以告诉.NET GC不要处理一些线程吗? 我正在研究重写一个相对较小的服务从C++到C语言的可能性。该服务有两个主要功能: 偶尔执行一次HTTP请求。它们涉及到一些高级任务,如JSON编码/解码、BASE64编码/解码和HTTP请求本身,其中C++不是很棒的;李> 执行许多实时的、与音频相关的任务,这些任务都有严格的截止日期,而C#并不可怕,c#,.net,multithreading,garbage-collection,C#,.net,Multithreading,Garbage Collection,实时任务由一个独立的库来处理,它自己处理线程,几乎不与服务的其余部分交互。服务的其余部分每隔5分钟左右向它提供一点从HTTP请求中获得的数据 问题是,由于实时部分有严格的截止日期,我真的不能容忍库线程上的GC暂停。在我自己的代码方面,GC应该有足够的时间在Web请求之间运行,但我也不能容忍它在我尝试向库提供数据时启动 我想我可以创建一个关键部分,垃圾收集器不会在其中开始使用,这解决了一半的问题 但是,我仍然不知道是否有办法告诉.NETGC不要去管那些不运行托管代码的特定线程。这可能吗?正如您所指

实时任务由一个独立的库来处理,它自己处理线程,几乎不与服务的其余部分交互。服务的其余部分每隔5分钟左右向它提供一点从HTTP请求中获得的数据

问题是,由于实时部分有严格的截止日期,我真的不能容忍库线程上的GC暂停。在我自己的代码方面,GC应该有足够的时间在Web请求之间运行,但我也不能容忍它在我尝试向库提供数据时启动

我想我可以创建一个关键部分,垃圾收集器不会在其中开始使用,这解决了一半的问题


但是,我仍然不知道是否有办法告诉.NETGC不要去管那些不运行托管代码的特定线程。这可能吗?

正如您所指出的,当应用程序配置为在工作站GC模式下运行时,垃圾收集器不会挂起执行本机代码的线程。在这种情况下,无论何时您的服务收到请求,我都会尝试这样的方式

    private bool _running = true;
    private int _workCounter = 0;
    private AutoResetEvent _workFlag = new AutoResetEvent(false);
    private void RunNoGCNativeCode(params object[] args)
    {
        // Increase the work counter to determine how many requests are being processed
        if (Interlocked.Increment(ref _workCounter) == 1)
        {
            // Try to start a No GC Region
            GC.TryStartNoGCRegion(1 * 1024 * 1024 * 1024, true);
        }
        // TODO: Prep data and execute your native code
        // TODO: Process response
        // TODO: Dispose of anything that is no longer in use and null objects as needed
        if (Interlocked.Decrement(ref _workCounter) == 0 && GCSettings.LatencyMode == GCLatencyMode.NoGCRegion)
        {
            GC.EndNoGCRegion();
        }
        // Notify Manual Collection thread work has been completed
        _workFlag.Set();
    }
在不同的线程上

    private void WaitForNoWorkThenGC()
    {
        // Continue running thread while in use
        while (_running)
        {
            // Wait for some work to be complete
            _workFlag.WaitOne();
            // If there is no work being processed call GC.Collect() 
            if (_workCounter == 0)
            {
                GC.Collect();
            }
        }
    } 
这将帮助您控制GC发生的时间,以最大限度地减少对应用程序的影响

至于托管代码,我没有发现任何迹象表明.NET垃圾收集可以“忽略”执行托管代码的特定线程。垃圾收集的所有当前模式(服务器、工作站、并发等)将在选择挂起托管代码时挂起所有执行托管代码的线程。请注意,某些GC模式在线程中可以有较短的暂停时间,这可能也会有所帮助。我也尝试过在实时c#应用程序中使用TryStartNoGCRegion(),但它总是忽略我的请求,因为我使用的内存量太大,我也找不到一种方法来指定仅在达到X内存限制后收集

但是,有两种可能的解决方案可以研究

  • 用于监视GC何时接近完全垃圾回收。如果在内存到达收集点之前手动释放一些内存,则可以避免垃圾收集
  • 在不同的应用程序进程中运行不同类型的请求?或者在收到它们时将它们传递给单独的应用程序进程。这样,每个应用程序不共享上下文,垃圾收集将分别处理
  • 没有检查,但是, 我将继承线程或任务,无论您使用什么 比如:

    那你就可以正常使用了

    var newThread = new SuppressedThread(DoWork);
    newThread.Start(42);
    

    你觉得怎么样?

    看。它有各种各样的警告。@ScottHannen,我也偶然发现了它(我在关于GC.TryStartNoGCRegion的一段中链接到了它)。我不认为它显示了将线程排除在垃圾收集之外的任何内容。CLR不能挂起正在忙于运行本机代码的线程。它也不必这样做,当它运行这样的代码时,任何对象根都不能更改。因此,无需“询问”,只需确保您的时间关键型代码是本机代码,并且在执行其工作时不会返回到托管方法,并且不会出错。@HansPassant,这有文档记录吗?如果是,那将是一个有效的答案。@HansPassant,我发现“”记录了工作站式垃圾回收的行为。我感谢研究工作,但我想指出,有文档证据表明工作站垃圾回收器不会中断运行本机代码的线程。请参阅,向下滚动到“比较工作站和服务器垃圾收集”。啊,是的,我的答案是特定于运行托管代码的线程的。在.NET应用程序调用本机代码之前和之后。换句话说,您回答了自己的问题,“如何告诉.NET在GC期间不要挂起执行本机代码的线程?-将应用程序配置为使用工作站GC模式,请参阅:Elementhttps://msdn.microsoft.com/en-us/library/ms229357%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396"@zneak只是想跟进一下,看看我更新的答案是否有帮助,谢谢。这有很多问题。1)
    螺纹
    密封;你不能继承它。2) 即使您可以从它继承,这也只会阻止线程本身的GC,而不会阻止在线程上创建的对象。3) 无法在C#中重写
    Finalize
    方法。而是使用终结器语法,如
    ~Foo()
    var newThread = new SuppressedThread(DoWork);
    newThread.Start(42);