【问题标题】:async and await code behaving differently if we run it from different processes如果我们从不同的进程运行 async 和 await 代码,它的行为会有所不同
【发布时间】: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.LastWriteFilter = control-fileInternalBufferSize 设置为 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 有大量请求,我的缓冲区经常溢出。

然后我想到了一个主意。 (asyncawaitTask 主战坦克一起救援)

  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,现在事情变得奇怪了,我的应用程序当我没有asyncawait 时,我面临InternalBufferOverflow 相同数量的控制文件 异常和相同数量的写入。

我再次使用一个控制台应用程序进行了测试(它同时承担了这两个职责),它运行良好。

那么,为什么两个控制台应用程序使asyncawait(以及Task)的魔力消失了,而一个控制台应用程序运行良好?

和进程间通信有关吗?

我想知道它是否可以在生产中工作,因为我将在 Web 应用程序中使用处理程序代码,并且其他一些进程可以通过网络编写这些文件。

【问题讨论】:

  • 工作的控制台应用程序是否在某个时候设置了表单? async/await 依赖于处理同步的SynchronizationContext。准系统控制台应用程序中是否有合适的应用程序?
  • @LasseV.Karlsen 它的简单控制台应用程序无与伦比。不涉及“UI 上下文”。
  • 请查看我的回答 here - async/await 在控制台应用程序中的工作方式与它在 UI 应用程序中的工作方式非常不同。
  • @EJoshuaS 但问题是为什么它在一个控制台应用程序的情况下有效,而不是在两个控制台应用程序的情况下?

标签: c# asynchronous async-await console-application filesystemwatcher


【解决方案1】:

最后,我能够弄清楚这一点,当我使用单个控制台应用程序时,我正在运行它的 exe(通过 cmd),但是当我尝试使用两个控制台应用程序时,我在 Visual Studio 中运行该应用程序(在发布模式下) )所以由于这个(带有视觉工作室的负载)我得到了例外,我责备asyncawait

因此,如果您正在处理紧凑的代码,请始终从 exe 运行您的应用程序。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-13
    • 1970-01-01
    • 2013-06-04
    • 1970-01-01
    • 2022-01-15
    相关资源
    最近更新 更多