将同步方法更改为异步 [英] Changing a synchronous method to async

查看:125
本文介绍了将同步方法更改为异步的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Google上搜索了很多,阅读了很多不同的noob教程,但是我不认为我应该做的是正确的事情.基本上,如果服务器已启动并正在运行,则现有的同步代码可以执行某些操作.有时,很少会出现服务器花费较长时间的情况,因此我想将其包装在一些重试逻辑中.我构建了一个完全愚蠢的控制台应用程序,以尝试了解异步和等待的工作方式,并提出了以下建议:

I've googled around a lot and read different noob tutorials, but I don't think I understand what the proper thing to do is. Basically there is existing code that is synchronous that does something if the server is up and running. Sometimes, very rarely, the server takes longer to come up so I wanted to wrap it in some retry logic. I built a completely stupid console app to try to understand how async and await work a little bit and came up with this:

    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函数代表我当前可以正常使用的函数,该函数通常在第一次使用时起作用.然后可以用

My LongTask function is representing my current function that does work that usually works the first time. Is it ok practice to then call this method with

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

假设这没问题,那么我基本上会在当前代码中为当前方法 DoWork()创建此代码.

Assuming that is 'ok', then I would basically create this in my actual code for my current method DoWork().

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

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

Basically just wrapping it in a Task.Run, changing the return type to Task. Then when I call this method later, I would do something like

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

这样我应该将先前的同步方法异步转换吗?预先感谢.

Is this way I should convert a previous sync method async? Thanks in advance.

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

pseudo code for DoWork(string directory, CancellationToken token)

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 .

The short answer is No, you cannot convert all types of synchronous code to asynchronous simply by wrapping the operation with Task.Run and making the method return Task.

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

Usually, asynchronous code makes sense when the operation in consideration might invoke some IO operations (file system read/write, network or web access, database access ... etc.).

例如,如果您有一种方法,该方法使用诸如 FileStream.Read 之类的同步方法从文件中读取一些数据,然后对该文件的内容进行某些CPU工作,则可以转换您的方法是异步的,方法是调用 FileStream.ReadAsync ,然后异步地等待,直到使用 await 关键字完成 ReadAsync ,然后开始工作文件的内容上(当然,您必须更改返回 Task 并使其成为 async 的方法).

For example, if you have a method that reads some data from a file using synchronous methods like FileStream.Read, and then does some CPU work on the contents of such file, then you can convert your method to be asynchronous by making it invoke FileStream.ReadAsync instead and then asynchronously wait until ReadAsync is done by using the await keyword and then work on the contents of the file (of course you have to change the method to return Task and to be async).

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

The benefit in this case is that there is no thread waiting for the IO operation to complete and threads are expensive.

没有线程等待IO操作完成的好处在ASP.NET网站这样的服务器应用程序中非常重要,因为您期望大量同时请求.但是,对于简单的应用程序,您可能不希望一开始就使用异步代码.

The benefit of not having threads waiting for IO operations to complete is very important in server applications like ASP.NET web sites where you expect a lot of simultaneous requests. However, for simple applications you might not want to bother with asynchronous code in the first place.

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

You can use Task.Run if you want to run multiple CPU intensive operations on multiple CPU cores.

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

For example, if you have 4 CPU cores, it makes sense to create 4 tasks via Task.Run to process some data. Consider the previous example, after you asynchronously wait for ReadAsync to complete, you can split the result of the read to 4 parts (assuming that the data is relatively large), and create 4 tasks via Task.Run, each will handle one part of the results. You can then asynchronously wait for the 4 tasks to complete using Task.WhenAll.

这篇关于将同步方法更改为异步的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆