异步等待(Async Await)不需要使用Task<T>方法

3
根据MSDN提供的以下示例,涉及到IT技术相关内容:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

// Add a using directive and a reference for System.Net.Http; 
using System.Net.Http;

namespace AsyncFirstExample
{
    public partial class MainWindow : Window
    {
        // Mark the event handler with async so you can use await in it. 
        private async void StartButton_Click(object sender, RoutedEventArgs e)
        {
            // Call and await separately. 
            //Task<int> getLengthTask = AccessTheWebAsync(); 
            //// You can do independent work here. 
            //int contentLength = await getLengthTask; 

            int contentLength = await AccessTheWebAsync();

            resultsTextBox.Text +=
            String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
        }


        // Three things to note in the signature: 
        //  - The method has an async modifier.  
        //  - The return type is Task or Task<T>. (See "Return Types" section.)
        //    Here, it is Task<int> because the return statement returns an integer. 
        //  - The method name ends in "Async."
        async Task<int> AccessTheWebAsync()
        { 
            // You need to add a reference to System.Net.Http to declare client.
            HttpClient client = new HttpClient();

            // GetStringAsync returns a Task<string>. That means that when you await the 
            // task you'll get a string (urlContents).
            Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");

            // You can do work here that doesn't rely on the string from GetStringAsync.
                DoIndependentWork();

            // The await operator suspends AccessTheWebAsync. 
            //  - AccessTheWebAsync can't continue until getStringTask is complete. 
            //  - Meanwhile, control returns to the caller of AccessTheWebAsync. 
            //  - Control resumes here when getStringTask is complete.  
            //  - The await operator then retrieves the string result from getStringTask. 
            string urlContents = await getStringTask;

            // The return statement specifies an integer result. 
            // Any methods that are awaiting AccessTheWebAsync retrieve the length value. 
            return urlContents.Length;
        }


        void DoIndependentWork()
        {
            resultsTextBox.Text += "Working . . . . . . .\r\n";
        }
    }
}

// Sample Output: 

// Working . . . . . . . 

// Length of the downloaded string: 41564.

如何替换异步Web请求调用:

我该如何用自己的代码块(其中包含简单的for循环)替换Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");?就像这样:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

// Add a using directive and a reference for System.Net.Http; 
using System.Net.Http;

namespace AsyncFirstExample
{
    public partial class MainWindow : Window
    {
        // Mark the event handler with async so you can use await in it. 
        private async void StartButton_Click(object sender, RoutedEventArgs e)
        {
            // Call and await separately. 
            //Task<int> getLengthTask = AccessTheWebAsync(); 
            //// You can do independent work here. 
            //int contentLength = await getLengthTask; 

            int contentLength = await AccessTheWebAsync();

            resultsTextBox.Text +=
            String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
        }


        // Three things to note in the signature: 
        //  - The method has an async modifier.  
        //  - The return type is Task or Task<T>. (See "Return Types" section.)
        //    Here, it is Task<int> because the return statement returns an integer. 
        //  - The method name ends in "Async."
        async Task<int> AccessTheWebAsync()
        { 
            // GetStringAsync returns a Task<string>. That means that when you await the 
            // task you'll get a string (urlContents).
            Task<string> getStringTask = GetMyString(); // here

            // You can do work here that doesn't rely on the string from GetStringAsync.
                DoIndependentWork();

            // The await operator suspends AccessTheWebAsync. 
            //  - AccessTheWebAsync can't continue until getStringTask is complete. 
            //  - Meanwhile, control returns to the caller of AccessTheWebAsync. 
            //  - Control resumes here when getStringTask is complete.  
            //  - The await operator then retrieves the string result from getStringTask. 
            string urlContents = await getStringTask;

            // The return statement specifies an integer result. 
            // Any methods that are awaiting AccessTheWebAsync retrieve the length value. 
            return urlContents.Length;
        }


        void DoIndependentWork()
        {
            resultsTextBox.Text += "Working . . . . . . .\r\n";
        }
    }
}

    private Task<string> GetMyString()
    {
        string str = string.Empty;
        for (int i = 0; i < 1000000000; i++)
        {
            // compute str using simple c# code
        }
        // How to return str now?
    }

1
GetMyString 实际上是否具有任何有用的异步功能呢?如果没有,当您将其与期望适当的异步代码(即它几乎立即返回,任务稍后完成)一起使用时,它将无法正常工作。 - Jon Skeet
2
你的问题具体是什么? - Ben Robinson
不,GetMyString 不是异步的。但我仍然想将调用变成异步的。 - yazanpro
3
@yazanpro,你的意思是你希望它在另一个线程中运行吗?这并不意味着它是异步的…… - Thomas Levesque
是的,我似乎希望它在另一个线程中运行。我一定混淆了这两个概念! - yazanpro
1个回答

5

如何返回str

像这样:

private async Task<string> GetMyString()
{
    string str = string.Empty;
    for (int i = 0; i < 1000000000; i++)
    {
        // compute str using simple c# code
    }
    return str;
}

然而,这并不太合理,因为 GetMyString 的实现不是异步的;你从未在其中使用 await,编译器会警告你。

如果你只是想在单独的线程中运行 GetMyString,请使其同步,并用 Task.Run 运行它:

private string GetMyString()
{
    string str = string.Empty;
    for (int i = 0; i < 1000000000; i++)
    {
        // compute str using simple c# code
    }
    return str;
}

...

Task<string> getStringTask = Task.Run(() => GetMyString());

使用单独的线程正是我所需要的。但是,为了使答案完整,可以请您详细说明如何以异步方式实现GetMyString,并指出如何防止由return str;引起的编译器错误。 - yazanpro
1
@yazanpro 不,你的实现思路不是异步的。例如,如果你实际上是从 Web 服务器接收数据,那么这是一种异步 I/O 操作,并且不会使用任何线程。你正在进行 CPU 工作,因此没有机会使用异步 I/O,只能使用并行性(在最佳情况下)。这两个概念非常不同,而 TaskTask<T> 的定义方式使得这种区别相当令人困惑。 - Luaan
2
@yazanpro 所以 Task.Run 返回的任务基本上是异步 I/O 到它刚创建的 CPU 工作线程,但你实际执行的工作仍然是 CPU 工作,而不是异步 I/O。 - Luaan
1
使用async关键字实现方法,但不使用await会引发编译器警告。您可以删除async关键字,改用"return Task.FromResult(str)"。 - Linky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接