标签: memory-mapped-files

附加调试器的C#代码非常慢; MemoryMappedFile的错?

我有一个客户端/服务器应用程序.服务器组件运行,以"远程处理"方式使用WCF(二进制格式化程序,会话对象).

如果我启动服务器组件并启动客户端,则服务器执行的第一项任务将在<0.5秒内完成.

如果我在连接了VS调试器的情况下启动服务器组件,然后启动客户端,则任务需要20秒才能完成.

没有代码更改 - 没有条件编译更改.无论我是否已经编译并运行32位,64位服务器组件,VS主机进程,没有VS主机进程,或者这些东西的任何组合,都会出现同样的情况.

可能很重要:如果我使用VS.NET 探查器(采样模式),那么应用程序运行速度就像没有连接调试器一样.所以我不能那样诊断它.刚检查,仪表模式也快速运行.对于并发性分析模式,同样快速.

关键数据:

  • 该应用程序使用相当繁重的多线程(标准线程池中的40个线程).无论如何,创建线程都会很快发生,而且不是一个慢点.有许多锁,WaitHandles和Monitor模式
  • 该应用程序完全没有例外.
  • 该应用程序不会创建控制台输出
  • 该应用程序完全是托管代码.
  • 该应用程序确实将磁盘上的几个文件映射到MemoryMappedFile:1x750MB和12x8MB以及一些较小的文件

测量性能:

  • 两种情况下CPU使用率都很低; 连接调试器时,CPU位于<1%
  • 两种情况下内存使用都很少; 两种情况下可能都是50或60MB
  • 发生了大量的页面错误(参考MMF),但是在附加调试器时它们发生得更慢
  • 如果VS宿主进程不使用,或基本上是"远程调试监视器"进场,则使用一个体面的CPU,并创建一个良好的数量页面错误的.但这不是问题发生的唯一时间
  • 无论客户端如何运行,都会看到性能差异.唯一要更改的变量是通过"从调试开始"vs从Explorer启动的服务器组件.

我的想法:

  • 调试时WCF速度慢?
  • MemoryMappedFiles在调试时会变慢吗?
  • 使用了40个线程 - 调试速度慢?也许Monitors/locks通知调试器?线程调度变得奇怪/上下文切换非常罕见?
  • 宇宙背景辐射赋予VS智慧和残酷的幽默感

所有人似乎都不太可能.

所以,我的问题:

  1. 为什么会这样?
  2. 如果#1未知,我该如何诊断/发现?

c# debugging performance .net-4.0 memory-mapped-files

9
推荐指数
2
解决办法
4315
查看次数

数据结构的最佳存储,以实现快速查找和持久性

脚本

我有以下方法:

public void AddItemSecurity(int itemId, int[] userIds)
public int[] GetValidItemIds(int userId)
Run Code Online (Sandbox Code Playgroud)

最初我在考虑存储在表单上:

itemId -> userId, userId, userId
Run Code Online (Sandbox Code Playgroud)

userId -> itemId, itemId, itemId
Run Code Online (Sandbox Code Playgroud)

AddItemSecurity基于我如何从第三方API获取数据,GetValidItemIds我是如何在运行时使用它的.

可能有2000个用户和1000万个项目.项目ID在表格上:2007123456,2010001234(前10位代表年份的10位数字).

AddItemSecurity不必执行超快,但GetValidIds需要亚秒.此外,如果现有更新,itemId我需要为列表中不再包含的用户删除该itemId.

我正在考虑如何以最佳方式存储它.最好在磁盘上(带缓存),但我希望代码可维护和清洁.

如果项目id从0开始,我考虑MaxItemId / 8为每个用户创建一个字节数组长度,如果项目存在与否则设置一个真/假位.这将限制每个用户的阵列长度超过1mb,并提供快速查找以及更新每个用户列表的简便方法.通过使用.Net 4框架将其作为内存映射文件持久化,我认为我也可以获得不错的缓存(如果机器有足够的RAM),而不是自己实现缓存逻辑.解析id,剥离年份,每年存储一个阵列可能是一个解决方案.

ItemId - > UserId []列表可以直接序列化到磁盘并使用法线FileStream进行读/写,以便持久保存列表并在发生更改时进行区分.

每次添加新用户时,所有列表也必须更新,但这可以在每晚完成.

我应该继续尝试这种方法,还是应该探索其他途径?我认为SQL服务器执行速度不够快,而且会产生开销(至少如果它托管在不同的服务器上),但我的假设可能是错误的.任何关于此事的想法或见解都表示赞赏.我想尝试解决它而不添加太多硬件:)

[更新2010-03-31]

我现在已经在以下条件下使用SQL Server 2008进行了测试.

  • 具有两列(userid,itemid)的表都是Int
  • 两列上的聚簇索引
  • 为180个用户添加了约800,000个项目 - 总计1.44亿行
  • 为SQL服务器分配4gb ram
  • 双核2.66ghz笔记本电脑
  • SSD磁盘
  • 使用SqlDataReader将所有itemid读入List
  • 遍历所有用户

如果我运行一个线程,它的平均值为0.2秒.当我添加第二个线程时,它会上升到0.4秒,这仍然可以.从那里开始,结果正在减少.添加第三个线程会带来很多查询,最多可达2个.第四个线程,最多4秒,第五个线程查询一些查询,最多50秒.

即使在一个线程上,CPU也在进行屋顶处理.我的测试应用程序需要一些由于快速循环,并sql其余.

这使我得出结论,它不会很好地扩展.至少不在我测试的硬件上.有没有办法优化数据库,比如存储每个用户的int数组而不是每个项目一个记录.但这使得删除项目变得更加困难.

[更新2010-03-31#2]

我使用相同的数据进行了快速测试,将其作为内存映射文件中的位.它表现得更好.六个线程产生的访问时间介于0.02s和0.06s之间.纯粹的记忆力.映射文件由一个进程映射,并由六个其他进程同时访问.并且由于sql base占用了4GB,磁盘上的文件占用了23mb.

.net c# sql-server memory-mapped-files data-structures

8
推荐指数
1
解决办法
2967
查看次数

Java内存映射文件?

Java中的内存映射文件是否适用于Windows的内存映射文件?或者它只是基于Java中的内存和文件常见操作的仿真?

java winapi memory-mapped-files

8
推荐指数
2
解决办法
1189
查看次数

Mutex的"安全"处理?

我经常从另一个进程正在写入的内存映射文件中读取并使用互斥锁来同步此操作.到目前为止,在我的几个测试中,这个工作正常,但是...如果我的应用程序在获取互斥锁之后和释放之前崩溃了怎么办?有没有办法保证互斥锁的发布,即使发生了这样的崩溃?

另外,我如何处理其他进程的崩溃,这可能还没有释放互斥锁呢?每次调用mutex.WaitOne()时,是否需要处理AbandonedMutexException?

现在我正在这样做:

public MyState GetState()
{
    MyState state = new State();
    this._mutex.WaitOne();
    try
    {
        state.X = this._mmView.ReadSingle(0);
        state.Y = this._mmView.ReadSingle(4);
        [..]
    }
    finally
    {
        this._mutex.ReleaseMutex();
    }
    return state;
}
Run Code Online (Sandbox Code Playgroud)

_mmView是我之前实例化的MemoryMappedViewAccessor.整个方法GetState()作为游戏循环的一部分被调用每个帧,因此大约每隔几毫秒.

PS:此外,还有其他明显的问题,为什么这可能会失败,我还没有提到?

c# mutex memory-mapped-files

8
推荐指数
1
解决办法
2203
查看次数

读取内存映射文件或内存映射视图访问器的所有内容,而不知道它的大小

我需要类似于ReadToEnd或ReadAllBytes的东西来使用MappedViewAccessor读取MemoryMappedFile的所有内容,如果我不知道它的大小,我该怎么办呢?

我已经搜索过了,我已经看到了这个问题,但这不是我要找的东西:

如何从.NET中的内存映射文件中快速读取字节?

编辑:

有一个问题,(int)stream.Length没有给我正确的长度,而是给出了内部缓冲区的大小!我需要刷新这个问题,因为它非常紧迫.

.net c# ipc accessor memory-mapped-files

8
推荐指数
3
解决办法
2万
查看次数

为什么 lsof 在 Mac 上将内存映射文件的文件描述符报告为 txt 而不是 mem?

lsof test在 Mac OS X 上运行时得到以下输出,其中test是内存映射文件的名称:

COMMAND     PID     USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
filesyste 40535 buildbot  txt    REG    1,6        3 2466028 test
Run Code Online (Sandbox Code Playgroud)

请注意,这txt是在FD现场报告的。但是,根据文档lsof

   FD         is the File Descriptor number of the file or:

                   mem  memory-mapped file;
                   txt  program text (code and data);
Run Code Online (Sandbox Code Playgroud)

那么问题来了:为什么是lsof报道txt而不是mem现场FD

该文件映射如下:

mmap(0, length, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0)
Run Code Online (Sandbox Code Playgroud)

其中length是长度,fd是文件的描述符。

macos mmap lsof memory-mapped-files

8
推荐指数
0
解决办法
1894
查看次数

是否可以在内存映射文件中存储python对象(特别是sklearn模型)?

我有几个占用大量内存的大型对象(sklearn模型),我想在几个进程之间共享它们.有没有办法做到这一点?

  • 它必须是"实时"对象,而不是序列化版本
  • 我知道有一个numpy数组的内存映射版本,它负责模型内存的重要部分 - 但使用它们需要对sklearn源代码进行重大更改,这很难维护

python shared-memory memory-mapped-files scikit-learn

8
推荐指数
1
解决办法
287
查看次数

如何使用File :: Map正确写入文件?

我经常使用File :: Map将特别小的文本文件映射到内存中,例如在那些上处理一些只读的正则表达式.现在我有一个用例,我需要在文件中替换一些文本并认为我仍然可以使用File::Map,因为它记录了以下内容:

文件被映射到一个可以像任何其他变量一样被读取的变量,并且可以使用标准的Perl技术(例如regexps和substr)来编写它.

虽然我有兴趣替换的数据在文件中被正确替换,但我丢失了数据,因为文件保持原始大小,最后数据被截断.新数据比旧数据略大.使用以下句子记录两件事情:

不建议直接写入内存映射文件

将新值截断为内存映射的大小

对两个警告的解释都不应该写任何东西File::Map,但它可能适用于一个人可以使用截断文件或整个文件大小根本没有改变的情况.但是第一个引用明确提到写入是支持的,没有任何例外.

那么,是否有一些特殊的方法可以安全地使用File::Map,例如增加底层文件等等?第一个警告使用了措辞directly,我觉得还有一些其他更好的支持写作方式?

我只是=~ s///在目前的映射视图上使用,这似乎是错误的方法.我甚至找不到任何人试图写File::Map任何东西,只有正式的测试完全按照我的方式进行,并期待我得到的警告.另外,看一下代码,似乎只有一个用例,其中写入根本不会产生警告,但我不明白我是如何触发的:

static int mmap_write(pTHX_ SV* var, MAGIC* magic) {
        struct mmap_info* info = (struct mmap_info*) magic->mg_ptr;
        if (!SvOK(var))
                mmap_fixup(aTHX_ var, info, NULL, 0);
        else if (!SvPOK(var)) {
                STRLEN len;
                const char* string = SvPV(var, len);
                mmap_fixup(aTHX_ var, info, string, len);
        }
        else if (SvPVX(var) != info->fake_address)
                mmap_fixup(aTHX_ var, info, SvPVX(var), SvCUR(var));
        else
                SvPOK_only_UTF8(var);
        return 0;
} …
Run Code Online (Sandbox Code Playgroud)

perl memory-mapped-files

8
推荐指数
2
解决办法
185
查看次数

Java中的内存映射大文件

是否可以在Java中对大型文件(多个GB)进行内存映射?

这种方法FileChannel看起来很有希望:

MappedByteBuffer map(FileChannel.MapMode mode, long position, long size)
Run Code Online (Sandbox Code Playgroud)

双方positionsize允许64位值-到目前为止,那么好。

MappedByteBuffer,但是,仅提供用于32位位置(get(int index)position(int newPosition)等)的方法,这似乎暗示我无法映射大于2 GB的文件。

我如何解决这个限制?

java nio memory-mapped-files

8
推荐指数
1
解决办法
375
查看次数

使用内存映射文件在 C++ 中解析二进制文件太慢

我正在尝试按整数解析二进制文件,以检查整数值是否满足某个条件,但循环非常慢。

此外,我发现memory-mapped files 是将文件快速读入内存的最快方法,因此我使用了以下Boost基于代码的代码:

unsigned long long int get_file_size(const char *file_path) {
    const filesystem::path file{file_path};
    const auto generic_path = file.generic_path();
    return filesystem::file_size(generic_path);
}

boost::iostreams::mapped_file_source read_bytes(const char *file_path,
                                         const unsigned long long int offset,
                                         const unsigned long long int length) {
    boost::iostreams::mapped_file_params parameters;
    parameters.path = file_path;
    parameters.length = static_cast<size_t>(length);
    parameters.flags = boost::iostreams::mapped_file::mapmode::readonly;
    parameters.offset = static_cast<boost::iostreams::stream_offset>(offset);

    boost::iostreams::mapped_file_source file;

    file.open(parameters);
    return file;
}

boost::iostreams::mapped_file_source read_bytes(const char *file_path) {
    const auto file_size = get_file_size(file_path);
    const auto mapped_file_source = read_bytes(file_path, 0, …
Run Code Online (Sandbox Code Playgroud)

c++ optimization memory-mapped-files micro-optimization

8
推荐指数
1
解决办法
185
查看次数