需要多线程内存管理器 [英] Need multi-threading memory manager

查看:245
本文介绍了需要多线程内存管理器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将不得不创建一个多线程项目,我已经看到实验(delphitools.info/2011/10/13/memory-manager-investigations),显示默认的Delphi内存管理器有多线程问题。





所以,我找到了这个SynScaleMM。任何人都可以给它一些反馈或类似的内存管理员?



谢谢

解决方案

我们的 SynScaleMM 仍然是实验性的。



编辑:查看更稳定的 ScaleMM2 和全新的 SAPMM 。但是我下面的说法还是值得的:你做的分配越少越好你的规模!



但是在多线程服务器环境。对于一些关键测试,缩放比FastMM4好得多。



但是内存管理器可能不是多线程应用程序中更大的瓶颈。 FastMM4可以很好的工作,如果你不强调它。



这里有一些(不是教条主义,只是从低级别的Delphi RTL的实验和知识)建议,如果你想在Delphi中写FAST多线程应用程序:




  • 始终使用 const 字符串或动态数组参数,例如 MyFunc(const aString:String),以避免每次调用分配一个临时字符串;

  • 避免使用字符串连接( s:= s +'Blabla'+ IntToStr(i)),但依赖于缓冲写入,如 TStringBuilder 在最新版本的Delphi中可用;

  • TStringBuilder 也不完美:例如,它将创建大量临时字符串用于添加一些数值数据,并且当您添加一些整数值时,将使用非常慢的 SysUtils.IntToStr()函数 - 我不得不重写很多低级功能,以避免我们的 SynCommons.pas 中定义的TTextWriter 类;

  • 不要滥用关键部分,让他们尽可能的小,但是如果您需要一些并发访问,请依赖某些原子修饰符。 InterlockedIncrement / InterlockedExchangeAdd ;

  • InterlockedExchange (来自SysUtils.pas)是一个更好的方式更新缓冲区或共享对象。您在线程中创建一些内容的更新版本,然后在一个低级CPU操作中,将共享指针交换到数据(例如 TObject 实例)。它将通过非常好的多线程缩放通知其他线程的更改。你必须要照顾数据的完整性,但它在实践中运行得很好。

  • 不要在线程之间共享数据,而是使自己的私有副本或依靠某些只读缓冲区( RCU 模式更适合缩放);

  • 不要使用索引访问字符串字符,而是依赖于一些优化的函数,例如 PosEx();

  • 不要混合 AnsiString / UnicodeString 类型的变量/函数,并通过Alt-F2检查生成的asm代码来跟踪任何隐藏的不需要的转换(例如调用UStrFromPCharLen );

  • 在<$ c中使用 var 参数$ c>程序而不是函数返回一个字符串(返回一个字符串的函数将会添加一个 UStrAsg / LStrAsg 调用,其中有一个LOCK将刷新所有CPU内核);

  • 如果可以,为了你的da ta或文本解析,使用指针和一些静态堆栈分配的缓冲区而不是临时字符串或动态数组;

  • 不要创建一个 TMemoryStream 每次你需要一个,但依靠一个你的类中的一个私有实例,已经有足够的内存大小,你可以使用位置来编写数据来检索数据,而不是更改其大小(这将是MM分配的内存块);

  • 限制您的类实例数量创建:尝试重用同一个实例,如果可以,在已分配的内存缓冲区上使用一些 record / object 指针,将数据映射到不复制到临时内存中; / li>
  • 始终使用测试驱动的开发,使用专用的多线程测试,试图达到最差的限制(增加线程数,数据内容,添加一些不连贯的数据,随机暂停,尝试强调网络或磁盘访问,基于实时数据的时间基准...);

  • 不要相信你的本能,而是在真实的数据和流程上使用准确的时间。



我们的开源框架中的这些规则,如果你看看我们的代码,你会发现很多真实的示例代码。


I will have to create a multi-threading project soon I have seen experiments ( delphitools.info/2011/10/13/memory-manager-investigations ) showing that the default Delphi memory manager has problems with multi-threading.

So, I have found this SynScaleMM. Anybody can give some feedback on it or on a similar memory manager?

Thanks

解决方案

Our SynScaleMM is still experimental.

EDIT: Take a look at the more stable ScaleMM2 and the brand new SAPMM. But my remarks below are still worth following: the less allocation you do, the better you scale!

But it worked as expected in a multi-threaded server environment. Scaling is much better than FastMM4, for some critical tests.

But the Memory Manager is perhaps not the bigger bottleneck in Multi-Threaded applications. FastMM4 could work well, if you don't stress it.

Here are some (not dogmatic, just from experiment and knowledge of low-level Delphi RTL) advice if you want to write FAST multi-threaded application in Delphi:

  • Always use const for string or dynamic array parameters like in MyFunc(const aString: String) to avoid allocating a temporary string per each call;
  • Avoid using string concatenation (s := s+'Blabla'+IntToStr(i)) , but rely on a buffered writing such as TStringBuilder available in latest versions of Delphi;
  • TStringBuilder is not perfect either: for instance, it will create a lot of temporary strings for appending some numerical data, and will use the awfully slow SysUtils.IntToStr() function when you add some integer value - I had to rewrite a lot of low-level functions to avoid most string allocation in our TTextWriter class as defined in SynCommons.pas;
  • Don't abuse on critical sections, let them be as small as possible, but rely on some atomic modifiers if you need some concurrent access - see e.g. InterlockedIncrement / InterlockedExchangeAdd;
  • InterlockedExchange (from SysUtils.pas) is a good way of updating a buffer or a shared object. You create an updated version of of some content in your thread, then you exchange a shared pointer to the data (e.g. a TObject instance) in one low-level CPU operation. It will notify the change to the other threads, with very good multi-thread scaling. You'll have to take care of the data integrity, but it works very well in practice.
  • Don't share data between threads, but rather make your own private copy or rely on some read-only buffers (the RCU pattern is the better for scaling);
  • Don't use indexed access to string characters, but rely on some optimized functions like PosEx() for instance;
  • Don't mix AnsiString/UnicodeString kind of variables/functions, and check the generated asm code via Alt-F2 to track any hidden unwanted conversion (e.g. call UStrFromPCharLen);
  • Rather use var parameters in a procedure instead of function returning a string (a function returning a string will add an UStrAsg/LStrAsg call which has a LOCK which will flush all CPU cores);
  • If you can, for your data or text parsing, use pointers and some static stack-allocated buffers instead of temporary strings or dynamic arrays;
  • Don't create a TMemoryStream each time you need one, but rely on a private instance in your class, already sized in enough memory, in which you will write data using Position to retrieve the end of data and not changing its Size (which will be the memory block allocated by the MM);
  • Limit the number of class instances you create: try to reuse the same instance, and if you can, use some record/object pointers on already allocated memory buffers, mapping the data without copying it into temporary memory;
  • Always use test-driven development, with dedicated multi-threaded test, trying to reach the worse-case limit (increase number of threads, data content, add some incoherent data, pause at random, try to stress network or disk access, benchmark with timing on real data...);
  • Never trust your instinct, but use accurate timing on real data and process.

I tried to follow those rules in our Open Source framework, and if you take a look at our code, you'll find out a lot of real-world sample code.

这篇关于需要多线程内存管理器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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