【问题标题】:TPL Dataflow TransformBlock Execution Sequence Seems Out Of Order / AsyncTPL 数据流 TransformBlock 执行序列似乎乱序/异步
【发布时间】:2017-04-21 21:02:55
【问题描述】:

我正在关注这个 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...

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

不应该首先调用TransformBlockConsole.WriteLines,因为我首先调用它,因为这将成为管道的一部分?此外,据我所知,我没有任何 async 代码,而且我不完全了解 TPL 数据流 的内部工作原理,所以为什么这似乎是在执行订购?

谢谢!

【问题讨论】:

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


    【解决方案1】:

    为什么在调用 TransformBlock 的 Console.WriteLines 之前执行 Press a key to exit 行?

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

    如果您想等待管道完成,则需要在 async 方法中阻止其 Completion Taskawait 完成:

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

    【讨论】:

    • 谢谢。因此,当各种块像这样在管道中链接在一起时 => //Connect the dataflow blocks to form a pipeline. // downloadString.LinkTo(createWordList); createWordList.LinkTo(filterWordList); filterWordList.LinkTo(findReversedWords); findReversedWords.LinkTo(printReversedWords); 演练代码的哪一部分确保前一个块的输出作为输入馈送到下一个块?例如:downloadString 的输出作为输入发送到 createWordList(但只有在 downloadString 完成之后,对吧?
    • @Shiva 例如:downloadString 的输出作为输入发送到 createWordList(但只有在 downloadString 完成后,对吗? 正确,LinkTo 将确保来自块被传递到链接块的输入。此外,您可以添加到LinkToDataflowLinkOptions 使得PropagateCompletiontrue。当您在第一个块上调用完成时,完成将传播通过您的管道,您将在管道中的最后一个块上完成await
    【解决方案2】:

    Post方法会在posted item存入block的输入队列后返回,不会等待处理完毕。

    来自MSDN documentation

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

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

    【讨论】:

      猜你喜欢
      • 2023-04-09
      • 1970-01-01
      • 1970-01-01
      • 2016-03-28
      • 1970-01-01
      • 1970-01-01
      • 2013-11-22
      • 2018-07-30
      • 1970-01-01
      相关资源
      最近更新 更多