TPL 数据流 TransformBlock 执行序列似乎乱序/异步

TPL Dataflow TransformBlock Execution Sequence Seems Out Of Order / Async

我正在关注这个 MSDN Walkthrough - Walkthrough: Creating a Dataflow Pipeline。我创建了一个 TransformBlock 并通过对它执行 Post 来执行它。

  // Process "The Adventurous Life of a Versatile Artist: Houdini" 
  //         by Harry Houdini.
  downloadString.Post("http://www.gutenberg.org/cache/epub/45370/pg45370.txt");

然后,我调用 Complete 方法并得到 Console.WriteLine("Press a key to exit:"); 行。

这是完整的代码。您也可以在此阶段在 this commit on my github repo.

中找到它
using System;
using System.Net.Http;
using System.Threading.Tasks.Dataflow;

namespace Palindromes.ConsoleApp
{
  class Program
  {
    static void Main(string[] args)
    {
      // 
      // Create members of the Pipeline
      //

      // Download the requested resource as a string

      var downloadString = new TransformBlock<string, string>
        ( url =>
          {
            Console.WriteLine($"Downloading from {url}...");
            string result = null;
            using (var client = new HttpClient())
            {
              // Perform a synchronous call by calling .Result
              var response = client.GetAsync(url).Result;

              if (response.IsSuccessStatusCode)
              {
                var responseContent = response.Content;

                // read result synchronously by calling .Result 
                result = responseContent.ReadAsStringAsync().Result;
                if (!string.IsNullOrEmpty(result))
                  Console.WriteLine($"Downloaded {result.Length} characters...");

              }
            }
            return result;
          }
        );

      // Process "The Adventurous Life of a Versatile Artist: Houdini" 
      //         by Harry Houdini.
      downloadString.Post("http://www.gutenberg.org/cache/epub/45370/pg45370.txt");
      downloadString.Complete();

      Console.WriteLine("Press a key to exit:");
      Console.ReadKey();
    }
  }
}

当我执行这个控制台应用程序时,我希望看到如下输出。

预期输出

Downloading from http://www.gutenberg.org/cache/epub/45370/pg45370.txt...
Downloaded 129393 characters...
Press a key to exit:

但这是实际输出。 (我已经 运行 多次显示相同的 Console.WriteLine 输出序列。

实际输出

Press a key to exit:
Downloading from http://www.gutenberg.org/cache/epub/45370/pg45370.txt...
Downloaded 129393 characters...

为什么 Press a key to exit 行在 TransformBlockConsole.WriteLine 行被调用之前执行?

不应该先调用 TransformBlockConsole.WriteLine,因为我首先调用它,而且这将成为管道的一部分?另外,据我所知,我没有任何 async 代码,我也不完全了解 TPL 数据流 的内部工作原理,所以为什么会出现这个乱序执行?

谢谢!

Why is the Press a key to exit line getting executed before the TransformBlock's Console.WriteLines get called?

Console.WriteLine("Press a key to exit:") 的调用发生在 TransformBlock 完成转换函数之前。发布到 TransfromBlock 的每个项目都将根据您的主要上下文进行异步处理。

继续前进,如果您想等待管道完成,您将需要阻止其 Completion Taskawaitasync 方法中完成:

private static async Task MainAsync() {
    // Process "The Adventurous Life of a Versatile Artist: Houdini" 
    //         by Harry Houdini.
    downloadString.Post("http://www.gutenberg.org/cache/epub/45370/pg45370.txt");
    downloadString.Complete();

    await downloadString.Completion;
}

Post 方法将 return 发布的项目存储在块的输入队列中后,它不会等待它被处理。

来自MSDN documentation

This method will return once the target block has decided to accept or decline the item, but unless otherwise dictated by special semantics of the target block, it does not wait for the item to actually be processed. For example, ActionBlock will return from Post as soon as it has stored the posted item into its input queue).

然后异步处理来自输入队列的项目。