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

时间:2017-04-21 21:02:55

标签: c# async-await task-parallel-library tpl-dataflow

我跟随 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 TransformBlock之前执行Console.WriteLine行?

首先要调用TransformBlock&#39; s Console.WriteLine,因为我首先要调用它,因为这将成为管道的一部分?另外,据我所知,我没有任何async代码,而且我不完全了解 TPL数据流的内部工作原理,为什么会这样做?似乎没有按顺序执行?

谢谢!

2 个答案:

答案 0 :(得分:1)

  

为什么在按下TransformBlock的Console.WriteLines之前按一个键退出行执行?

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;
}

答案 1 :(得分:1)

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

来自MSDN documentation

  

一旦目标块决定接受或拒绝该项,此方法将返回,但除非目标块的特殊语义另有规定,否则它不会等待实际处理该项。例如,一旦将已发布的项目存储到其输入队列中,ActionBlock将立即从Post返回。

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