将同步方法更改为异步

本文关键字:异步 同步方法 | 更新日期: 2023-09-27 18:29:27

我在谷歌上搜索了很多,阅读了不同的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

这是我应该转换以前的同步方法async的方式吗?

编辑

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
    }
}

将同步方法更改为异步

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

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

例如,如果您有一个方法,使用FileStream.Read等同步方法从文件中读取一些数据,然后对该文件的内容执行一些CPU工作,然后,您可以将方法转换为异步方法,方法是调用FileStream.ReadAsync,然后使用await关键字异步等待ReadAsync完成,然后处理文件的内容(当然,您必须更改方法以返回Task并成为async)。

这种情况的好处是没有线程在等待IO操作完成,而且线程成本很高。

在像ASP.NET网站这样的服务器应用程序中,不让线程等待IO操作完成的好处非常重要,因为在这些应用程序中需要大量的同时请求。然而,对于简单的应用程序,您可能不想首先使用异步代码。

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

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