c# - 异步递归方法

标签 c# asynchronous recursion task-parallel-library

好吧...所以我正在将我的一些简单使用的应用程序转换为停止使用后台工作系统来执行标准异步操作。我使用 async 从头开始​​构建了一个 WPF 应用程序并且它运行得非常好,所以我想转换其余部分以执行相同的操作(只是让我更容易阅读代码)。在这种情况下,我使用一种方法来清除目录,然后从存储我们的构建的机器(编译和存放它们的地方)复制文件和目录。我遇到了“空”方法的问题,我必须递归地使它正常运行。这是目前的方法(有些地方是错误的):

public static Task Empty(string targetDir)
    {
        return Task.Run(() =>
            {
                foreach (var directory in Directory.GetDirectories(targetDir))
                {
                    Empty(directory);
                    string[] filelist2 = Directory.GetFiles(directory);
                    foreach (string files in filelist2)
                    {
                        File.SetAttributes(files, FileAttributes.Normal);
                        File.Delete(files);
                    }

                    if (!Directory.EnumerateFileSystemEntries(directory).Any())
                    {
                        Directory.Delete(directory, false);
                    }
                }
                string[] filelist = Directory.GetFiles(targetDir);
                foreach (string files in filelist)
                {
                    File.SetAttributes(files, FileAttributes.Normal);
                    File.Delete(files);
                }
            });
    }

现在它所做的是删除所有文件和子目录。它使用 backgroundworker(之前没有 Task 或任何东西)工作,但尝试在 Task 中运行最终会弹出一个关于无法找到文件的异常。我的猜测是它与线程有关,但我似乎无法弄清楚是什么。

有什么可能导致问题的想法吗?当它尝试在文件上设置属性时失败(每次都不是同一个文件......似乎一旦递归循环多次它就无法改变文件属性)。

最佳答案

等待递归调用

public static Task Empty(string targetDir)
{
    return Task.Run(async () =>
        {
            foreach (var directory in Directory.GetDirectories(targetDir))
            {
                await Empty(directory);
                string[] filelist2 = Directory.GetFiles(directory);
                foreach (string files in filelist2)
                {
                    File.SetAttributes(files, FileAttributes.Normal);
                    File.Delete(files);
                }

                if (!Directory.EnumerateFileSystemEntries(directory).Any())
                {
                    Directory.Delete(directory, false);
                }
            }
            string[] filelist = Directory.GetFiles(targetDir);
            foreach (string files in filelist)
            {
                File.SetAttributes(files, FileAttributes.Normal);
                File.Delete(files);
            }
        });
}

编辑 这里也有很多需要改进的地方。 您正在删除文件两次。要解决此问题,您可以像这样减少代码

public static Task<bool> Empty(string targetDir)
{
    return Task.Run(async () =>
    {
        foreach (var directory in Directory.GetDirectories(targetDir))
        {
            if (await Empty(directory))
                Directory.Delete(directory, false);
        }
        var retval = true;
        foreach (string file in Directory.GetFiles(targetDir))
        {
            try
            {
                File.SetAttributes(file, FileAttributes.Normal);
                File.Delete(file);
            }
            catch(Exception ex)
            {
                // something went wrong: log ex
                retval = false;
            }
        }
        return retval;
    });
}

但这仍然不是真正有效的,因为您仍在等待递归调用返回。正如@Servy 所建议的,将创建许多无用的任务。 让我向您展示一种仅通过一项任务即可完成此操作的方法。 我们定义一个同步函数:

public static bool Empty(string targetDir)
{
    foreach (var directory in Directory.GetDirectories(targetDir))
    {
        if (Empty(directory))
            Directory.Delete(directory, false);
    }
    var retval = true;
    foreach (string file in Directory.GetFiles(targetDir))
    {
        try
        {
            File.SetAttributes(file, FileAttributes.Normal);
            File.Delete(file);
        }
        catch(Exception ex)
        {
            // something went wrong: log ex
            retval = false;
        }
    }
    return retval;    
}

现在我们定义它的异步版本:

public static Task<bool> EmptyAsync(string targetDir)
{
    return Task.Run(() => this.Empty(targetDir));
}

这可能比每次调用调用都创建任务具有相同/更好的性能。

关于c# - 异步递归方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25286459/

相关文章:

Swift:监听 url 属性然后下载照片

C#异步套接字问题

c++ - 递归传递字符串而不需要重新创建

c# - 从 3.1.2 版升级到 5.0.3 版后,Entity Framework 核心 Include() 不起作用

C# - 如何使用 LINQ to Objects 创建不可变对象(immutable对象)

c# - 获取CancellationToken延迟值

c# - 带有标记列表的解释器递归波兰表示法

c++ - 根据用户输入控制插入BST

c# - 在C#中处理大文本文件

C# 5 async/await 线程机制感觉不对?