草庐IT

c# - 具有 C# 结构的生产者/消费者?

coder 2023-06-04 原文

我有一个处理请求的单例对象。每个请求大约需要一毫秒才能完成,通常更少。该对象不是线程安全的,它需要特定格式的请求,封装在 Request 中。类,并返回结果为Response .该处理器有另一个生产者/消费者,通过套接字发送/接收。

我实现了生产者/消费者方法来快速工作:

  • 客户准备 RequestCommand命令对象,包含 TaskCompletionSource<Response>和预期的 Request .
  • 客户端将命令添加到“请求队列”(Queue<>)并等待 command.Completion.Task .
  • 另一个线程(和实际背景 Thread )从“请求队列”中拉出命令,处理 command.Request , 生成 Response并使用 command.Completion.SetResult(response) 表示命令已完成.
  • 客户继续工作。

但是当做一个小的内存基准测试时,我看到很多这些对象被创建并且在内存中最常见的对象列表中名列前茅。请注意,没有内存泄漏,GC 可以在每次触发时很好地清理所有内容,但显然如此多的对象被快速创建,使得 Gen 0 非常大。我想知道更好的内存使用是否会产生更好的性能。

我正在考虑将其中一些对象转换为结构以避免分配,特别是现在有一些新功能可用于 C# 7.1。但我看不出有什么办法。

  • 值类型可以在堆栈中实例化,但如果它们从线程传递到线程,它们必须复制到堆栈A->堆和堆->堆栈B 我猜。此外,当在队列中排队时,它会从堆栈到堆。
  • 单例对象是真正异步的。有一些内存处理,但 90% 的时间需要调用外部并通过内部生产者/消费者。
  • ValueTask<>似乎不适合这里,因为事情是异步的。
  • TaskCompletionSource<>有一个状态,但它是 object ,所以它会被装箱。
  • 该命令还从一个线程跳转到另一个线程。
  • 回收对象仅适用于命令本身,其内容无法回收(TaskCompletionSource<>string)。

有什么方法可以利用结构来减少内存使用或/和提高性能?还有其他选择吗?

最佳答案

Value types can be instantiated in the stack, but if they pass from thread to thread, they must be copied to the stackA->heap and heap->stackB I guess.

不,这根本不是真的。但是你在这里有一个更深层次的问题:

立即停止将结构视为存在于堆栈中的想法。当你用一百万个整数创建一个整数数组时,你认为这四百万字节的整数存在于你的一百万字节堆栈中吗?当然不是。

事实上,堆栈与堆与值类型没有任何关系。开始说“短期分配池”和“长期分配池”,而不是“堆栈和堆”。 生命周期较短的变量是从短期分配池中分配的,无论该变量是否包含 int 或对对象的引用。一旦你开始正确地考虑变量生命周期,那么你的推理就变得非常简单了。 显然,短命的东西存在于短期池中。

那么:当你将一个结构体从一个线程传递到另一个线程时,它是否存在于“堆上”? 这个问题很荒谬,因为值不是堆砌的东西变量是存储的东西;变量存储值。

那么:将类转换为结构是否会因为“这些结构可以存在于堆栈上”而提高性能?不,当然不是。 引用类型和值类型之间的相关区别不在于它们所在的位置,而在于它们的复制方式。值类型按值复制,引用类型按引用复制,引用复制是最快的复制。

I see LOTS of these objects being created and topping the list of most common object in memory. Note that there is no memory leak, the GC can clean everything up nicely each time triggers, but obviously so many objects being created fast, makes Gen 0 very big. I wonder if a better memory usage may yield better performance.

好的,现在我们来谈谈您问题的合理部分。 这是一个很好的观察结果,可以用科学来检验。您应该做的第一件事是使用分析器来确定第 0 代集合对应用程序性能的实际负担。

可能这个负担不是你程序中最慢的东西,事实上它是无关紧要的。在这种情况下,您现在将知道将精力集中在真正的问题上,而不是追查不是真正问题的内存分配问题。

假设您发现 gen 0 集合确实影响了您的表现;你能做什么?是让更多的东西结构的答案吗?这可以工作,但你必须非常小心:

  • 如果结构本身包含引用,你只是将问题推到了一层,你还没有解决它。
  • 如果结构体大于引用大小(当然它们几乎总是如此),那么现在您通过复制整个结构体而不是复制引用来复制它们,并且您已经将 GC 时间问题换成了复制时间问题。这可能是胜利,也可能是失败; 用科学找出它是什么

当我们在 Roslyn 遇到这个问题时,我们非常仔细地考虑并进行了 很多 实验。我们采用的策略通常不是将东西移到堆栈上。相反,我们使用分析器确定了内存中在任何时候处于事件状态的每种类型有多少小的、短生命周期的对象,然后对这些对象实现池化策略。你需要一个小 object ,你把它从水池里拿出来。完成后,将其放回池中。发生的情况是,您最终会在池中得到 O(任何时候事件的对象数量),它很快就会被移入第 2 代堆;然后,您会大大降低对第 0 代堆的收集压力,同时增加相对稀有的第 2 代收集的成本。

我并不是说那是您的最佳选择。我是说我们在罗斯林也遇到了同样的问题,我们用科学解决了它。你也可以这样做。

关于c# - 具有 C# 结构的生产者/消费者?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52818477/

有关c# - 具有 C# 结构的生产者/消费者?的更多相关文章

  1. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  2. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  3. Ruby Sinatra 配置用于生产和开发 - 2

    我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm

  4. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  5. ruby-on-rails - 在 Rails 中调试生产服务器 - 2

    您如何在Rails中的实时服务器上进行有效调试,无论是在测试版/生产服务器上?我试过直接在服务器上修改文件,然后重启应用,但是修改好像没有生效,或者需要很长时间(缓存?)我也试过在本地做“脚本/服务器生产”,但是那很慢另一种选择是编码和部署,但效率很低。有人对他们如何有效地做到这一点有任何见解吗? 最佳答案 我会回答你的问题,即使我不同意这种热修补服务器代码的方式:)首先,你真的确定你已经重启了服务器吗?您可以通过跟踪日志文件来检查它。您更改的代码显示的View可能会被缓存。缓存页面位于tmp/cache文件夹下。您可以尝试手动删除

  6. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  7. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  8. ruby-on-rails - Rails 3.1 中具有相同形式的多个模型? - 2

    我正在使用Rails3.1并在一个论坛上工作。我有一个名为Topic的模型,每个模型都有许多Post。当用户创建新主题时,他们也应该创建第一个Post。但是,我不确定如何以相同的形式执行此操作。这是我的代码:classTopic:destroyaccepts_nested_attributes_for:postsvalidates_presence_of:titleendclassPost...但这似乎不起作用。有什么想法吗?谢谢! 最佳答案 @Pablo的回答似乎有你需要的一切。但更具体地说...首先改变你View中的这一行对此#

  9. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  10. ruby-on-rails - 一般建议和推荐的文件夹结构 - Sinatra - 2

    您将如何构建一个简单的Sinatra应用程序?我正在制作,我希望该应用具有以下功能:“应用程序”更像是一个包含所有信息的管理仪表板。然后另一个应用程序将通过REST访问信息。我还没有创建仪表板,只是从数据库中获取东西session和身份验证(尚未实现)您可以上传图片,其他应用可以显示这些图片我已经使用RSpec创建了一个测试文件通过Prawn生成报告目前的设置是这样的:app.rbtest_app.rb因为我实际上只有应用程序和测试文件。到目前为止,我已经将Datamapper用于ORM,将SQLite用于数据库。这是我的第一个Ruby/Sinatra项目,所以欢迎任何和所有建议-我应

随机推荐