【问题标题】:Better way to implement the following long running thread in C#在 C# 中实现以下长时间运行的线程的更好方法
【发布时间】:2018-06-03 18:54:12
【问题描述】:

我有一个应用程序,它有一个等待事件(例如接收目录中的文件)并将该文件发布到 API 的主线程。这部分工作正常。

另一方面,由于某些原因,主线程可能会丢失一些文件。所以,我已经设置了一个后台线程来运行整个应用程序生命周期清理那些丢失的文件,如下所示:

public virtual void MissedFileHandler()
{
     if (_missedFileHandlerThread == null || !_missedFileHandlerThread.IsAlive)
     {
          _missedFileHandlerThread = new Thread(new ThreadStart(ClearMissedFiles));
          _missedFileHandlerThread.IsBackground = true;
          _missedFileHandlerThread.Start();
     }
}

protected virtual void ClearMissedFiles()
{
     while (true)
     {
         string[] missedFiles = new string[] { };
         missedFiles = Directory.GetFiles(ConfigurationHelper.applicationRootDirectory, "*.txt", SearchOption.TopDirectoryOnly);
         Parallel.ForEach(missedFiless, (currentMissedFile) =>
         {
             bool isFileInUse = true;
             isFileInUse = FileHelper.CheckIfFileInUse(filesInUseCollection, currentMissedFile)
             if (!isFileInUse)
             {
                 bool isHttpTransferSuccess = false;
                 isHttpTransferSuccess = FileHelper.SendFileToApi(userid, currentMissedFile);
             if (isHttpTransferSuccess)
             {
                  File.Delete(currentMissedFile);

             }
         }
     });
     Thread.Sleep(1000);
     }
  }

请注意,由于某些其他原因,不能将此作为 Windows 服务或调度程序运行。所以,我确实需要一个后台工作人员来定期清理丢失的文件。我检查了 TimerWaitHandles 但不太确定如何使用它们来实现以下内容。

这两个进程(新文件的主要偶数处理程序和后台清理程序被调用的方式是,在主应用程序线程中,我将实例化类并在应用程序启动时调用方法。它是Thread.Sleep() 和@987654325 @ 这让我很困扰,正在寻找更好的方法。谢谢。

【问题讨论】:

  • 使用文件观察器检测该目录中的新文件。
  • 如果这个后台任务“有能力”做和主线程一样的工作,为什么他们都做这个工作?为什么不把它全部留给后台线程呢?

标签: c# multithreading while-loop


【解决方案1】:

您可以使用文件监视器来检测该目录中的新文件。

private void watch()
{
  FileSystemWatcher watcher = new FileSystemWatcher();

  // Set your path with this
  watcher.Path = path;

  // Subscribe to event
  watcher.Changed += new FileSystemEventHandler(OnChanged);
  watcher.EnableRaisingEvents = true;
}

【讨论】:

  • 谢谢!我会试试这个,看看它是否适用于我的用例。如果它可靠地工作,我可以完全避免使用两个线程。如果可行,将接受作为答案。
  • 此代码的问题将是响应失败。文件在使用吗? HTTP 传输是否成功。这个答案是一个好的开始,但它不是一个完整的解决方案。
【解决方案2】:

尝试使用 Microsoft 的响应式框架。然后你可以这样做:

IObservable<Unit> fileChanges =
    Observable
        .Using(() =>
        {
            var fsw = new FileSystemWatcher();
            fsw.Path = path;
            fsw.EnableRaisingEvents = true;
            return fsw;
        }, fsw =>
            Observable
                .FromEventPattern<FileSystemEventHandler, FileSystemEventArgs>(
                    h => fsw.Changed += h,
                    h => fsw.Changed -= h))
        .Select(ep => Unit.Default);

IObservable<Unit> periodically =
    Observable
        .Interval(TimeSpan.FromSeconds(30.0))
        .Select(x => Unit.Default);

IObservable<string> clearMissedFiles =
    fileChanges
        .Merge(periodically)
        .SelectMany(u => Directory.GetFiles(ConfigurationHelper.applicationRootDirectory, "*.txt", SearchOption.TopDirectoryOnly))
        .Where(f => !FileHelper.CheckIfFileInUse(filesInUseCollection, f))
        .SelectMany(f => Observable.Start(() => FileHelper.SendFileToApi(userid, f)), (f, s) => new { file = f, success = s })
        .Where(x => x.success)
        .Select(x => x.file);

IDisposable subscription =
    clearMissedFiles
        .Subscribe(f => File.Delete(f));

这会监视文件系统并定期检查。并且并行调用 API,不会因为尝试一次删除多个文件而导致 O/S 悲痛。

在退出前只需致电subscription.Dispose() 进行清理。

NuGet "System.Reactive" 获取位,然后引用 using System.Reactive.Linq 以显示扩展。

【讨论】:

    猜你喜欢
    • 2019-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多