首页 文章

将同步方法更改为异步

提问于
浏览
2

我已经google了很多并阅读了不同的noob教程,但我不认为我理解正确的做法是什么 . 基本上,如果服务器启动并运行,则存在同步的现有代码 . 有时,很少,服务器需要更长时间才能启动,所以我想将它包装在一些重试逻辑中 . 我构建了一个完全愚蠢的控制台应用程序,试图了解如何异步并等待工作一点点,并提出了这个:

private static int counter = 0;

    static void Main(string[] args)
    {
        DoIt();
        Console.ReadLine();
    }

    static bool LongTask()
    {
        if (counter == 2)
        {
            Console.WriteLine("finally true");
            Thread.Sleep(1000);
            return true;
        }
        counter++;
        Console.WriteLine("false");
        Thread.Sleep(1000);
        return false;
    }

    public static Task<bool> WrapperLongTask()
    {
        Console.WriteLine("wrapper called");
        return Task.Run(() => LongTask());            
    }

    public static async Task DoIt()
    {
        Console.WriteLine("hi");
        var result = await WrapperLongTask();
        while (result != true)
        {
            result = await WrapperLongTask();
            Console.WriteLine("inside while loop");
        }
        Console.WriteLine($"outside while loop {result}");
        Console.WriteLine("bye");
    }

我的LongTask函数表示我当前的函数,它通常在第一次工作时起作用 . 是否可以练习然后调用此方法

Task.Run(() => LongTask())

假设那是'ok',那么我基本上会在我的当前方法 DoWork() 的实际代码中创建它 .

Task DoWorkAsync(....) {
     return Task.Run(() => DoWork()
}

基本上只是将它包装在Task.Run中,将返回类型更改为Task . 然后,当我稍后调用此方法时,我会做类似的事情

var x = await DoWorkAsync;
// do more stuff with x

这是我应该转换以前的同步方法异步?提前致谢 .

编辑:

DoWork的伪代码(字符串目录,CancellationToken令牌)

var files = Directory.GetFiles(directory, "*", SearchOption.AllDirectories);
foreach (var file in files) {
    try {
       token.ThrowIfCancellationRequested();
       var fileName = Path.GetFileName(file);
       // check if file already exists on server, if not, upload it
    }
    catch (Exception exception) {
       // error handling
    }
}

1 回答

  • 3

    简短的答案是否,您不能简单地通过使用 Task.Run 包装操作并使方法返回 Task 来将所有类型的同步代码转换为异步 .

    通常,当考虑的操作可能调用某些IO操作(文件系统读/写,网络或Web访问,数据库访问等)时,异步代码是有意义的 .

    例如,如果您有一个方法使用同步方法(如 FileStream.Read )从文件中读取某些数据,然后某些CPU处理此类文件的内容,那么您可以将方法转换为异步,方法是调用 FileStream.ReadAsync 而不是然后异步等待 ReadAsync 完成后使用 await 关键字,然后处理文件的内容(当然你必须改变方法返回 Task 并成为 async ) .

    在这种情况下的好处是没有线程等待IO操作完成并且线程很昂贵 .

    没有线程等待IO操作完成的好处在ASP.NET网站等服务器应用程序中非常重要,在这些应用程序中您需要大量的同时请求 . 但是,对于简单的应用程序,您可能不希望首先考虑异步代码 .

    如果要在多个CPU核心上运行多个CPU密集型操作,可以使用 Task.Run .

    例如,如果您有4个CPU内核,则通过 Task.Run 创建4个任务来处理某些数据是有意义的 . 考虑前面的例子,在异步等待 ReadAsync 完成之后,你可以将读取的结果拆分为4个部分(假设数据相对较大),并通过 Task.Run 创建4个任务,每个任务将处理结果的一部分 . 然后,您可以使用 Task.WhenAll 异步等待4个任务完成 .

相关问题