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
行在 TransformBlock
的 Console.WriteLine
行被调用之前执行?
不应该先调用 TransformBlock
的 Console.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 Task
或 await
在 async
方法中完成:
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 发布的项目存储在块的输入队列中后,它不会等待它被处理。
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).
然后异步处理来自输入队列的项目。
我正在关注这个 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
的 Console.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 Task
或 await
在 async
方法中完成:
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 发布的项目存储在块的输入队列中后,它不会等待它被处理。
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).
然后异步处理来自输入队列的项目。