【问题标题】:How to check if recursive function has finished?如何检查递归函数是否完成?
【发布时间】:2016-08-19 23:09:42
【问题描述】:

我正在为我的游戏制作补丁程序。修补程序检查 ftp 服务器上每个文件的大小与用户计算机上的本地文件的大小,如果不同,则从 ftp 服务器下载新文件。

我想添加一条显示“更新完成!X 个文件已更新”的打印消息。当它检查了所有文件但我知道该功能何时结束?

private void CheckForUpdates(string ftpPath, string localPath)
{
    FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpPath);
    request.Credentials = new NetworkCredential(ftpUser, ftpPass);
    request.Method = WebRequestMethods.Ftp.ListDirectory;
    FtpWebResponse response = (FtpWebResponse)request.GetResponse();
    Stream responseStream = response.GetResponseStream();
    StreamReader reader = new StreamReader(responseStream);

    List<string> files = new List<string>();

    string line = reader.ReadLine();
    while (!string.IsNullOrEmpty(line))
    {
        if (line != "." && line != ".." && line != ".htaccess")
        {
            files.Add(line);
        }

        line = reader.ReadLine();
    }

    response.Close();
    responseStream.Close();
    reader.Close();

    foreach (string file in files)
    {
        string newFtpPath = ftpPath + "/" + file;
        string newLocalPath = localPath + "/" + file;

        new Thread(() => AppendText("Checking " + newLocalPath + Environment.NewLine)).Start();

        if (IsFile(newFtpPath))
        {
            if (File.Exists(newLocalPath))
            {
                if (!IsFileEqual(newFtpPath, newLocalPath))
                {
                    new Thread(() => AppendText(file + " is out of date or corrupted. Patching in progress..." + Environment.NewLine)).Start();
                    new Thread(() => Download(newFtpPath, newLocalPath)).Start();
                }  
            }
            else
            {
                new Thread(() => AppendText(file + " is missing. Patching in progress..." + Environment.NewLine)).Start();
                new Thread(() => Download(newFtpPath, newLocalPath)).Start();
            }
        }
        else
        {
            if (!Directory.Exists(newLocalPath))
            {
                new Thread(() => AppendText(file + " is missing. Patching in progress..." + Environment.NewLine)).Start();
                Directory.CreateDirectory(newLocalPath);
            }

            new Thread(() => CheckForUpdates(newFtpPath, newLocalPath)).Start();
        }
    }
}

【问题讨论】:

  • 第一次调用该方法后你就知道了。所以在第一次调用递归函数之后的下一行执行。我通常会放入静态计数器以确保我不会无限期地递归开始(当我测试时)
  • 我看到你的问题是你正在产生新的线程。我肯定会跟踪您正在创建多少线程并使用信号量之类的东西来控制它
  • 想了想。我不一定会在线程中使用递归,它相当复杂,附带各种问题。我只会使用标志和一个while循环来安排再次检查更新的需要。或者重新考虑需求
  • 也许使用 Thread.Join 来确保在您进入下一次检查更新时所有事情都已完成
  • 旁注:其中一些线程似乎是不必要的。例如,AppendText 操作真的足够长来证明它自己的线程是正确的吗? (对我来说似乎有点矫枉过正)。例如,它是否可以与下载操作结合使用,或者只是同步运行?

标签: c# recursion ftp


【解决方案1】:

好的,所以我通过添加线程数解决了这个问题。

我看到你的问题是你正在产生新的线程。我会 肯定会跟踪您正在创建的线程数,并且 使用信号量之类的东西来控制它

当我需要深入研究文件时,添加线程数

threadCount++;
new Thread(() => CheckForUpdates(newFtpPath, newLocalPath)).Start();

并在函数结束时检查是否只有 1 个线程

if(threadCount == 1)
    //print end message
else
    threadCount--;

感谢大家的帮助!

【讨论】:

  • 是的,实际上是我的一个建议:)。顺便说一句,如果 threadCount 是一个字段,请确保将其标记为“易失性”。
  • 要不要也让更新文件数的字段不定?
  • 如果您从多个线程更新它,是的。不过,您可以避免这种情况,只需从“主”功能更新它(当然,除非您想在更新之前确保下载确实成功)。
【解决方案2】:

这取决于;如果您所做的只是打印一种方法,那么它可能无处不在。

但是,如果您希望发生其他事情(或者您可能希望将来发生其他事情),您可以随时提出事件。这实际上是一种相当常见的模式,尤其是在它是异步操作的情况下(听起来它是一个有意义的模式,因为它可能是一个长期运行的任务)。

如果您使用的是任务并行,这实际上可以帮助您了解它何时完成(至少对于调用者而言)。

您的另一个问题将是知道您正在创建的线程何时完成(因为否则即使您作为一个整体同步运行该方法,它返回的事实并不能保证所有线程都已完成他们的工作)。当然,这取决于您所说的“完成”的含义——如果“完成”是指“该方法已将控制权返回给其调用者并且所有相关的工作都已完成”,或者只是“该方法已将控制权返回给它的调用者”呼叫者。” (换句话说,如果该方法创建的某些线程仍在下载文件,则该方法是否可以被视为“完成”?如果您指望这些在该方法将控制权返回给其调用者时完成,这将是经典的比赛条件)。

如果您愿意,您可以使用任务并行来帮助您了解线程是否已完成。另一种(一种愚蠢但有效的)方法是保留某种“正在运行的线程”的变量(以线程安全的方式更新) - 每次生成一个新线程时,你都会以线程安全的方式增加计数每次其中一个完成时,它都会减少计数(再次以线程安全的方式)。 (如果您不使用任务,出于性能原因,您还可以考虑为这些任务使用线程池,而不是每次都创建一个新线程)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-15
    • 2015-11-25
    • 2018-03-18
    • 1970-01-01
    • 2021-03-17
    • 1970-01-01
    • 2016-05-07
    • 1970-01-01
    相关资源
    最近更新 更多