【问题标题】:Should I have multiple threads when using FileSystemWatcher?使用 FileSystemWatcher 时应该有多个线程吗?
【发布时间】:2012-11-01 18:15:27
【问题描述】:

我有一个 MVC3 Web 应用程序,用户通过该应用程序将文本文件上传到服务器上的 APP Data/Upload 文件夹。要求是将这些新上传的文件通过 FTP 传输到另一台服务器上的文件夹中。我在监视此上传文件夹的控制台应用程序中使用了 FileSystemWatcher。完全创建文件后,我将这个新生成的文件传输到 FTP 文件夹。

我担心的是,如果多个实例/用户从 Web 应用程序上传文件,我的控制台应用程序将如何处理这种情况?例如,我是否需要有一个队列并使用例如下面的FileProcesser 在不同的线程上处理文件?

public class FileProcessor
{
    private readonly Queue<string> files = new Queue<string>();
    private Thread thread;
    private readonly EventWaitHandle waitHandle = new AutoResetEvent(true);
    private static readonly object lockObject = new object();

    private volatile bool shouldStop = false;

    #region Helper methods

    private static bool IsFileUploadComplete(string path)
    {
        try
        {
            using (File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None))
            {
                return true;
            }
        }
        catch (IOException)
        {
            return false;
        }
    }

    private void ProcessFile(string path)
    {
        // Check if Result file has been completely created / uploaded
        int maximumProcessRetries = 5;
        int delayBeforeRetry = 5000; //in milliseconds, 5 seconds

        int attempts = 0;

        while (true)
        {
            if (IsFileUploadComplete(path))
            {
                //1. Open in existing IE process on Instrument Workstation
                var p = new System.Diagnostics.Process();
                var s = new System.Diagnostics.ProcessStartInfo(Settings1.Default.RSLSM_URL);
                s.UseShellExecute = true;
                s.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
                p.StartInfo = s;
                p.Start();

                //2. Open in new IE process on Instrument workstation
                //System.Diagnostics.Process.Start("IEXPLORE.EXE", "www.yahoo.com");

                break;
            }
            attempts += 1;
            if (attempts >= maximumProcessRetries)
            {
                // Log error and send out notifications to RSLMS Database or Email RSLMS Admin group?
                break;
            }
            Thread.Sleep(delayBeforeRetry);
        }

        // Add any logic after the file has been processed
        //File.Delete(path);
    }

    private void Work()
    {
        while (!shouldStop)
        {
            string path = String.Empty;
            lock (lockObject)
            {
                if (files.Count > 0)
                {
                    path = files.Dequeue();
                }
            }

            if (!String.IsNullOrEmpty(path))
            {
                // Process the file
                ProcessFile(path);
            }
            else
            {
                // If no files are left to process then wait
                waitHandle.WaitOne();
            }
        }
    }

    #endregion

    #region Methods

    public void EnqueueFile(string path)
    {
        // Queue the file
        lock (lockObject)
        {
            files.Enqueue(path);
        }

        // Initialize and start the worker thread when the first file is queued
        // or when it has been stopped and thus terminated.
        if (thread == null || shouldStop)
        {
            thread = new Thread(new ThreadStart(Work));
            thread.Start();
        }
        // If the thread is waiting then start it
        else if (thread.ThreadState == ThreadState.WaitSleepJoin)
        {
            waitHandle.Set();
        }
    }

    public void StopProcessing()
    {
        shouldStop = true;
    }

    #endregion
}

【问题讨论】:

  • 不,文件系统观察器在它们自己的线程上运行。

标签: c# filesystemwatcher


【解决方案1】:

您的 FileSystemWatcher 已在其自己的线程上停止运行,并通知您的服务器代码发生了某些事情(在您的情况下创建了一个文件)。

如果 args 传递给您的代码,它会提供已创建的文件列表,您可以通过该文件列表进行处理。在您的进程运行期间引发的任何事件都将在另一个线程上运行或排队,具体取决于您的锁定策略。

不过,一般来说,当我收到一个事件时,我会从 Directory.GetFiles 中获取所有文件的列表并处理该列表。它保证我不会丢失 Watcher 事件中的任何文件。

如果要在生产环境中运行,您需要摆脱该控制台应用程序并让您的进程作为 Windows 服务运行。控制台应用程序太脆弱,任何人都可以走到该控制台前终止。

【讨论】:

  • 我同意,我会将此代码移动到 Windows 服务,该服务将始终运行并监视文件夹中的文件。如果服务器必须重新启动,服务将自动重新启动。我将运行一些测试来查看文件系统的可靠性,因为我的要求是在文件创建后立即处理文件,而不是按指定的时间间隔处理。我担心锁定,但你已经解决了我的问题。谢谢
  • docs 中确实建议“尽可能缩短事件处理代码”。以防止 FileSystemWatcher 的内部缓冲区溢出。这是否表明如果您必须做很多工作(OP 正在阻塞网络 I/O 调用,最多 5 次重试尝试在两次尝试之间等待 5 秒)您应该在另一个线程上执行此操作? (在 OP 的情况下,他也可能只进行异步 I/O 调用)
猜你喜欢
  • 2016-07-02
  • 2019-10-08
  • 1970-01-01
  • 2012-03-20
  • 2010-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多