简体   繁体   English

异步编程:等待非异步的函数内部

[英]Asynchronous Programming: await inside a function that is not async

First the question: Can I use await inside a function that is not marked as async ?? 首先是问题:我可以在未标记为异步的函数中使用await吗?

Now the details. 现在的细节。 I was reading this post Hololens- Capturing Photo... and as you can see the author posted some code. 我正在读这篇文章Hololens-捕捉照片......正如你所看到的那样,作者发布了一些代码。 Among it this 其中就是这个

 void Start ()
    {
        getFolderPath();
        while (!haveFolderPath)
        {
            Debug.Log("Waiting for folder path...");
        }
        Debug.Log("About to call CreateAsync");
        PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated);
        Debug.Log("Called CreateAsync");
    }


    async void getFolderPath()
    {
        StorageLibrary myPictures = await Windows.Storage.StorageLibrary.GetLibraryAsync(Windows.Storage.KnownLibraryId.Pictures);
        Windows.Storage.StorageFolder savePicturesFolder = myPictures.SaveFolder;
        Debug.Log("savePicturesFolder.Path is " + savePicturesFolder.Path);
        folderPath = savePicturesFolder.Path;
        haveFolderPath = true;
    }

Now notice how the getFolderPath returns void (as an event handler) but the documentation says that these methods can't be awaited. 现在注意getFolderPath如何返回void(作为事件处理程序),但是文档说这些方法是无法等待的。 The author instead await by using a while loop. 作者改为等待使用while循环。

But what if I do this 但是如果我这样做会怎么样

     void Start ()
        {
            await getFolderPath();

            Debug.Log("About to call CreateAsync");
            PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated);
            Debug.Log("Called CreateAsync");
        }


     //Notice how now it returns Task
        async Task getFolderPath()
        {
            StorageLibrary myPictures = await Windows.Storage.StorageLibrary.GetLibraryAsync(Windows.Storage.KnownLibraryId.Pictures);
//.....
        }

Can I do this? 我可以这样做吗? (notice that Start() is not Async) (注意Start()不是Async)

People tend to forget what's behind async and await . 人们往往会忘记asyncawait的背后。

No, you can't await in a method that's not async but you can call ContinueWith on the returned Task and provide explicit continuation that executes only when the task is complete: 不,你不能在一个非async的方法中await ,但你可以在返回的Task上调用ContinueWith并提供仅在任务完成时执行的显式延续:

class Example
{
    public void Start()
    {
        getFolderPath()
           .ContinueWith(t =>
           {                   
               Console.WriteLine("...");
           });
    }

    async Task getFolderPath()
    {
        await Task.Delay(1000);
    }
}

That's equivalent to 这相当于

class Example
{
    public async Task Start()
    {
        await getFolderPath();
        Console.WriteLine("...");
    }


    async Task getFolderPath()
    {
        await Task.Delay(1000);
    }
}

You can not await function calls without marking the method as async . 您不能await不将方法标记为async情况下await函数调用。 So your second example will not compile. 所以你的第二个例子不会编译。 But you can mark the Start method as async . 但您可以将Start方法标记为async

Async await is a non blocking method to wait for execution of functions. Async await是一种等待执行函数的非阻塞方法。 In this case, the execution will stop at the await in the GetFolderPath method, but while this will wait, the execution in the Start method will continue. 在这种情况下,执行将在GetFolderPath方法中的await处停止,但是这将等待,Start方法中的执行将继续。 I assume, that because of this, the author uses the while loop to wait for the execution of getFolderPath to finish. 我假设,因此,作者使用while loop等待getFolderPath的执行完成。

The answer to your first question is No, you can't . 你的第一个问题的答案是否定的,你不能 From the official documentation 从官方文档

await can only be used in an asynchronous method modified by the async keyword. await只能在async关键字修改的异步方法中使用。 Such a method, defined by using the async modifier and usually containing one or more await expressions, is referred to as an async method. 通过使用async修饰符定义并且通常包含一个或多个await表达式的这种方法称为异步方法。

If you want to await the execution of the async method getFolderPath inside the start method, you need to update the signature to be 如果要在start方法中等待执行异步方法getFolderPath ,则需要将签名更新为

public async Task Start ()
{
    await getFolderPath();

    Debug.Log("About to call CreateAsync");
    PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated);
    Debug.Log("Called CreateAsync");
}

In the async await context, Task as a return type, means that the task does not return a value, which is equivalent to void in the synchronous approach. async await上下文中, Task作为返回类型,意味着任务不返回值,这在同步方法中等效于void if for example, you needed to return an string from an asynchronous task, you would need to have public async Task<string> GetFoo() . 例如,如果您需要从异步任务返回一个string ,则需要使用public async Task<string> GetFoo()

Overall, I think the code you from the example you are looking at needs some reviewing. 总的来说,我认为您正在查看的示例中的代码需要进行一些审核。

You could explicitly wait on the GetFolderPath method to finish: 您可以显式等待GetFolderPath方法完成:

    void Start ()
    {
        getFolderPath().Wait();

        Debug.Log("About to call CreateAsync");
        PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated);
        Debug.Log("Called CreateAsync");
    }


 //Notice how now it returns Task
    async Task getFolderPath()
    {
        StorageLibrary myPictures = await Windows.Storage.StorageLibrary.GetLibraryAsync(Windows.Storage.KnownLibraryId.Pictures);
        //.....
    }

But then you are turning the asynchronous method in a synchronous one , since Wait is a blocking method (but that is what happens in the while loop anyway). 但是之后你将异步方法转换为同步方法 ,因为Wait是一种阻塞方法(但这就是在while循环中发生的事情)。

If your aim is to keep the operation asynchronous, you have to go with Daniel Ormeño's suggestion: 如果您的目标是使操作保持异步,则必须遵循DanielOrmeño的建议:

    async Task Start ()
    {
        await getFolderPath();

        Debug.Log("About to call CreateAsync");
        PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated);
        Debug.Log("Called CreateAsync");
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM