【发布时间】:2017-08-16 04:50:40
【问题描述】:
请耐心等待这个冗长的问题。
场景:
我在 root-directory 上有一个 FileSystemWatcher,它正在监视 control-file 上每个 control-directory 中的 LastWrite 变化.看起来像这样:-
根目录(
FileSystemWatcher实例正在监视这个根目录)|
|-----控制目录_0 \控制文件
\ data-file|-----控制目录_1\控制文件
\ data-file|-----控制目录_2 \控制文件
\ data-file|-----控制目录_3 \控制文件
\ data-file............更相似的结构(但只有一个根目录)
对不起,我的创意绘图。
我面临的问题是,根目录内可能有很多控制目录(大约200-500个)以及控制目录的 控制文件,我有一个数据文件(在每个文件中),其中正在进行连续写入。
我在关注NotifyFilter.LastWrite 和Filter = control-file。
InternalBufferSize 设置为 4KB(请不要要求增加此值,我不允许修改它,并且由于要求将其设置为 8KB(默认值),我不能为每个 FileSystemWatcher >control-file 因为它会占用大量宝贵的非分页内存)。
我的EventHandler 看起来像这样
private void OnChange(Object sender, FileSystemEventArgs eventArgs)
{
//result = CPU bound work here
//evaluating result
}
目前,我正在处理 300 个控制文件。由于 data-file 上发生了大量写入,并且 control-file 有大量请求,我的缓冲区经常溢出。
然后我想到了一个主意。 (async 和 await 与 Task 主战坦克一起救援)
async private void OnChange(Object sender, FileSystemEventArgs eventArgs)
{
var result = await Task.Run(() => Work.CPUboundWork());
//evaluating result
}
它运行良好,我能够处理大量请求(即使测试了 1000 个事件,只有 4KB 缓冲区)。
现在是有趣的部分。我如何测试它?
涉及两个实体,一是写入控件或数据文件,二是处理写入控件所产生的事件-文件。所以我上去创建了一个控制台应用程序,它可以完成这两件事。
static void Main(string[] args)
{
int controlFileCount = Convert.ToInt32(args[0]);
string basePath = args[1];
//CreateFolderStructure(basePath, controlFileCount); for first run.
FileSystemWatcher baseDirectoryWatcher = new FileSystemWatcher();
SetupFileSystemWatcher(baseDirectoryWatcher, basePath);
WriteToControlFilesParallely(basePath, controlFileCount);
Console.Read();
}
public void SetupFileSystemWatcher(FileSystemWatcher baseDirectoryWatcher, string path)
{
//setting properties of the watcher.
baseDirectoryWatcher.NotifyFilter = NotifyFilter.LastWrite;
baseDirectoryWatcher.Filter = "control-file";
baseDirectoryWatcher.InternalBufferSize = 4096;
baseDirectoryWatcher.Path = path;
baseDirectoryWatcher.IncludeSubdirectories = true;
baseDirectoryWatcher.EnableRaisingEvents = true;
}
public void WriteToControlFilesParallely(string basePath, int controlFileCount)
{
Parallel.For(0, controlFileCount, (i) =>
{
string filePath = Helper.GetFilePath(basePath, i);
Helper.WriteData(filePath, "data");
});
}
接下来,我用两个控制台应用程序进行了测试:-
首先,负责将数据并行写入各个控制文件——(Writer_App)。
其次,负责处理事件——(Event_Handling_App)。
注意:核心中没有代码更改,但现在我不是在同一个控制台应用程序中编写和处理事件,而是从一个控制台应用程序编写并处理另一个表单。
所以我将两个 entities 从我的旧控制台应用程序中分离出来(开始模拟实际环境)。现在我通过首先运行 Event_Handling_App 开始测试,然后通过运行 Writer_App 写入 control-file,现在事情变得奇怪了,我的应用程序当我没有async 和await 时,我面临InternalBufferOverflow 相同数量的控制文件 异常和相同数量的写入。
我再次使用一个控制台应用程序进行了测试(它同时承担了这两个职责),它运行良好。
那么,为什么两个控制台应用程序使
async和await(以及Task)的魔力消失了,而一个控制台应用程序运行良好?和进程间通信有关吗?
我想知道它是否可以在生产中工作,因为我将在 Web 应用程序中使用处理程序代码,并且其他一些进程可以通过网络编写这些文件。
【问题讨论】:
-
工作的控制台应用程序是否在某个时候设置了表单?
async/await依赖于处理同步的SynchronizationContext。准系统控制台应用程序中是否有合适的应用程序? -
@LasseV.Karlsen 它的简单控制台应用程序无与伦比。不涉及“UI 上下文”。
-
请查看我的回答 here - async/await 在控制台应用程序中的工作方式与它在 UI 应用程序中的工作方式非常不同。
-
@EJoshuaS 但问题是为什么它在一个控制台应用程序的情况下有效,而不是在两个控制台应用程序的情况下?
标签: c# asynchronous async-await console-application filesystemwatcher