用可恢复函数等待C++在C++中的异步编程

如你所知,我们最近发布了 Visual C++编译器2013年11月CTP . 在这个CTP的许多功能之一是支持可恢复的功能和等待。在这篇博文中,我想介绍一些例子,这些特性使使用异步API编程的体验变得更加简单。

null

例1

我们要看的第一个例子是官方 Windows 8.1文件选取器示例 . 如果使用VisualStudio2013“构建并运行”打开此示例的解决方案,您将看到如下所示的应用程序。选择此示例中的选项4将打开“文件选取器”对话框,该对话框允许您保存简单的文本文件。

在项目文件Scenario4.xaml.cpp中,成员函数“Scenario4::SaveFileButtonu Click”包含打开文件选择器并写入保存的文件位置的实现。为了简洁起见,我删除了一些代码注释。

无等待代码:

void Scenario4::SaveFileButton_Click(Object^ sender, RoutedEventArgs^ e)
{
    rootPage->ResetScenarioOutput(OutputTextBlock);
 
    FileSavePicker^ savePicker = ref new FileSavePicker();
    savePicker->SuggestedStartLocation = PickerLocationId::DocumentsLibrary;
 
    auto plainTextExtensions = ref new Platform::Collections::Vector<String^>();
    plainTextExtensions->Append(".txt");
    savePicker->FileTypeChoices->Insert("Plain Text", plainTextExtensions);
    savePicker->SuggestedFileName = "New Document";
 
    create_task(savePicker->PickSaveFileAsync()).then([this](StorageFile^ file)
    {
        if (file != nullptr)
        {
            CachedFileManager::DeferUpdates(file);
            create_task(FileIO::WriteTextAsync(file, file->Name)).then([this, file]()
            {
                create_task(CachedFileManager::CompleteUpdatesAsync(file)).then([this, file]

                    (FileUpdateStatus status)

                {
                    if (status == FileUpdateStatus::Complete)
                        OutputTextBlock->Text = "File " + file->Name + " was saved.";
                    else
                        OutputTextBlock->Text = "File " + file->Name + " couldn't be saved.";
                });
            });
        }
        else
        {
            OutputTextBlock->Text = "Operation cancelled.";
        }
    });
}

以上代码使用 PPL任务 通过提供lambda来处理这些API的结果来调用Windows运行时异步API。

现在让我们对此代码进行一些更改:

  • 我假设您已经下载并安装了 11月CTP .
  • 在“项目属性”中,将“平台”工具集更改为“ Visual C++编译器NOV 2013 CTP(CTPYNOV2013)
  • 打开文件Scenario4.xaml.h,在类“Scenario4”中添加一个具有以下签名的私有函数:
void SaveFileButtonWithAwait() __resumable;
  • 打开文件Scenario4.xaml.cpp,在现有include语句下面添加以下内容:
#include <pplawait.h>
  • 在同一个文件中,转到现有成员函数“Scenario4::SaveFileButtonu Click”并注释掉其所有内容。而是向新添加的成员函数添加一个简单调用:
SaveFileButtonWithAwait();
  • 提供我们先前添加到头文件的成员函数的实现。代码如下所示:

带等待的代码:

void Scenario4::SaveFileButtonWithAwait() __resumable
{
    rootPage->ResetScenarioOutput(OutputTextBlock);
 
    FileSavePicker^ savePicker = ref new FileSavePicker();
    savePicker->SuggestedStartLocation = PickerLocationId::DocumentsLibrary;
 
    auto plainTextExtensions = ref new Platform::Collections::Vector<String^>();
    plainTextExtensions->Append(".txt");
    savePicker->FileTypeChoices->Insert("Plain Text", plainTextExtensions);
    savePicker->SuggestedFileName = "New Document";
 
    auto file = __await savePicker->PickSaveFileAsync();
    if (file != nullptr)
    {
        CachedFileManager::DeferUpdates(file);
        __await FileIO::WriteTextAsync(file, file->Name);
        auto status = __await CachedFileManager::CompleteUpdatesAsync(file);
        if (status == FileUpdateStatus::Complete)
        {
            OutputTextBlock->Text = "File " + file->Name + " was saved.";
        }
        else
        {
            OutputTextBlock->Text = "File " + file->Name + " couldn't be saved.";
        }
    }
    else
    {
        OutputTextBlock->Text = "Operation cancelled.";
    }
}

上面的代码使用wait to–well–wait来等待异步API的结果。如果您将此代码(使用await)与前面的代码(使用PPL任务)进行对比,您会同意,虽然两者都完成了任务,但后面的代码肯定更好看。

例2

另一个示例(不是在线示例,而是在实际应用程序中使用)是下面的代码。它基本上调用Windows运行时filepickerapi来选择多个图片,然后创建多个任务来将所有选定的文件复制到应用程序的临时文件夹中。在继续之前,它需要等待所有文件被复制。

无等待代码:

void XamlSpiro::MainPage::loadImagesWithPPL()
{
    auto openPicker = ref new FileOpenPicker();
    openPicker->SuggestedStartLocation = PickerLocationId::PicturesLibrary;
    openPicker->ViewMode = PickerViewMode::Thumbnail;
    openPicker->FileTypeFilter->Append("*");
 
    task<IVectorView<StorageFile^>^>(openPicker->PickMultipleFilesAsync()).then([this]

        (IVectorView<StorageFile^>^ fileVector)

    {
        for (auto file : fileVector)
        {
            m_copyTasks.push_back(create_task(file->CopyAsync(

                ApplicationData::Current->TemporaryFolder,

                file->Name, NameCollisionOption::ReplaceExisting)));

        }
 
        when_all(begin(m_copyTasks), end(m_copyTasks)).then([this](std::vector<StorageFile^> results)
        {
            for (auto copiedFile : results)
            {
                InputFilesVector->Append(copiedFile);
            }
        }).then([this]()
        {
            DisplayImages();
        });
    });
}

带等待的代码:

void XamlSpiro::MainPage::loadImagesWithAwait() __resumable
{
    auto openPicker = ref new FileOpenPicker();
    openPicker->SuggestedStartLocation = PickerLocationId::PicturesLibrary;
    openPicker->ViewMode = PickerViewMode::Thumbnail;
    openPicker->FileTypeFilter->Append("*");
 
    auto fileVector = __await openPicker->PickMultipleFilesAsync();
 
    for (auto file : fileVector)
    {
        m_copyTasks.push_back(create_task(file->CopyAsync(ApplicationData::Current->TemporaryFolder,

            file->Name, NameCollisionOption::ReplaceExisting)));

    }
 
    auto results = __await when_all(begin(m_copyTasks), end(m_copyTasks));
    for (auto copiedFile : results)
    {
        InputFilesVector->Append(copiedFile);
    }
    DisplayImages();
}

在这种情况下,一个微妙的区别是,我们并不是不必要地为每个CopySync调用调用await。那将是次优的。相反,我们仍在为所有复制操作创建单个任务,并在whenu all操作上调用await only,以便只等待所需的时间,不多也不少。

您可能知道,Windows应用商店世界充满了异步Windows运行时API。因此,这些功能对商店应用程序的开发特别有帮助。它们提供了一种同步的方式来思考需要编写异步调用的代码。我们希望您能尝试这些功能,并让我们知道您的反馈。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享