我有一个客户端/服务器应用程序.服务器组件运行,以"远程处理"方式使用WCF(二进制格式化程序,会话对象).
如果我启动服务器组件并启动客户端,则服务器执行的第一项任务将在<0.5秒内完成.
如果我在连接了VS调试器的情况下启动服务器组件,然后启动客户端,则任务需要20秒才能完成.
没有代码更改 - 没有条件编译更改.无论我是否已经编译并运行32位,64位服务器组件,VS主机进程,没有VS主机进程,或者这些东西的任何组合,都会出现同样的情况.
可能很重要:如果我使用VS.NET 探查器(采样模式),那么应用程序运行速度就像没有连接调试器一样.所以我不能那样诊断它.刚检查,仪表模式也快速运行.对于并发性分析模式,同样快速.
关键数据:
WaitHandles和Monitor模式测量性能:
我的想法:
所有人似乎都不太可能.
所以,我的问题:
脚本
我有以下方法:
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进行了测试.
如果我运行一个线程,它的平均值为0.2秒.当我添加第二个线程时,它会上升到0.4秒,这仍然可以.从那里开始,结果正在减少.添加第三个线程会带来很多查询,最多可达2个.第四个线程,最多4秒,第五个线程查询一些查询,最多50秒.
即使在一个线程上,CPU也在进行屋顶处理.我的测试应用程序需要一些由于快速循环,并sql其余.
这使我得出结论,它不会很好地扩展.至少不在我测试的硬件上.有没有办法优化数据库,比如存储每个用户的int数组而不是每个项目一个记录.但这使得删除项目变得更加困难.
[更新2010-03-31#2]
我使用相同的数据进行了快速测试,将其作为内存映射文件中的位.它表现得更好.六个线程产生的访问时间介于0.02s和0.06s之间.纯粹的记忆力.映射文件由一个进程映射,并由六个其他进程同时访问.并且由于sql base占用了4GB,磁盘上的文件占用了23mb.
Java中的内存映射文件是否适用于Windows的内存映射文件?或者它只是基于Java中的内存和文件常见操作的仿真?
我经常从另一个进程正在写入的内存映射文件中读取并使用互斥锁来同步此操作.到目前为止,在我的几个测试中,这个工作正常,但是...如果我的应用程序在获取互斥锁之后和释放之前崩溃了怎么办?有没有办法保证互斥锁的发布,即使发生了这样的崩溃?
另外,我如何处理其他进程的崩溃,这可能还没有释放互斥锁呢?每次调用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:此外,还有其他明显的问题,为什么这可能会失败,我还没有提到?
我需要类似于ReadToEnd或ReadAllBytes的东西来使用MappedViewAccessor读取MemoryMappedFile的所有内容,如果我不知道它的大小,我该怎么办呢?
我已经搜索过了,我已经看到了这个问题,但这不是我要找的东西:
编辑:
有一个问题,(int)stream.Length没有给我正确的长度,而是给出了内部缓冲区的大小!我需要刷新这个问题,因为它非常紧迫.
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是文件的描述符。
我有几个占用大量内存的大型对象(sklearn模型),我想在几个进程之间共享它们.有没有办法做到这一点?
我经常使用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) 是否可以在Java中对大型文件(多个GB)进行内存映射?
这种方法FileChannel看起来很有希望:
MappedByteBuffer map(FileChannel.MapMode mode, long position, long size)
Run Code Online (Sandbox Code Playgroud)
双方position并size允许64位值-到目前为止,那么好。
MappedByteBuffer,但是,仅提供用于32位位置(get(int index),position(int newPosition)等)的方法,这似乎暗示我无法映射大于2 GB的文件。
我如何解决这个限制?
我正在尝试按整数解析二进制文件,以检查整数值是否满足某个条件,但循环非常慢。
此外,我发现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# ×4
.net ×2
java ×2
.net-4.0 ×1
accessor ×1
c++ ×1
debugging ×1
ipc ×1
lsof ×1
macos ×1
mmap ×1
mutex ×1
nio ×1
optimization ×1
performance ×1
perl ×1
python ×1
scikit-learn ×1
sql-server ×1
winapi ×1