C# Producer/Consumer 设置,如果有 UI,Consumer 永远不会工作?
C# Producer/Consumer setup, Consumer never works if there's a UI?
我正在尝试制作一个为用户收集数据并下载的桌面应用程序。我之前使用的设置相当糟糕,一旦找到数据就调用异步下载,但我想转移到 producer/consumer 设置,因为它确实清理了我的很多代码并减少了我必须传递的方法参数的数量。
我用这个作为例子来关闭 (https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/how-to-implement-a-producer-consumer-dataflow-pattern) 并且效果很好。但是,我的应用程序也有一个 UI。这不是一个 UI 需要在程序执行它的时候工作,UI 基本上只是设置参数。我很高兴它被锁定了。它应该是。但是当我将项目(从那个link)移动到缓冲区的设置和 consumer.Wait() 到一个方法中时,当 UI 的按钮被点击时调用(运行程序),消费者从不行动。
通过日志记录,并仅使用 link 中几乎没有修改的版本,制作人将准确无误地提供我所期望的内容。但它永远不会超过 consumer.Wait()。它只会坐在那里。具体来说,它永远不会超过 "while (await source.OutputAvailableAsync()){"。它只是永远等待,而我可以保证通过 target.Post().
正确发送项目
我猜测这可能与没有足够的可用线程或其他原因有关?就像消费者饿死一样?我不确定。我所能找到的都是想要交互式 UI 的人,而我绝对不需要。但似乎我的 UI 和消费者在竞争。如果我从 main 方法中删除 window,而只是从该 Microsoft 文档中放置 main class,则完全没有问题。我只是不知道如何过去。
编辑:我的代码,虽然在我尝试解决这个问题时非常混乱,但在将其切换回长期解决方案之前。
private static void Produce(ITargetBlock<KeyValuePair<string, string>> target)
{
// In a loop, fill a buffer with random data and
// post the buffer to the target block.
for (var i = 0; i < 100; i++)
{
// Create an array to hold random byte data.
var buffer = new KeyValuePair<string, string>(DateTime.Now.ToString("yyyy-M-d") + " profile",
"http://www.orseu-concours.com/451-615-thickbox/selor-test-de-raisonnement-abstrait-niveau-a.jpg");
// Post the result to the message block.
target.Post(buffer);
Console.WriteLine(buffer);
}
// Set the target to the completed state to signal to the consumer
// that no more data will be available.
target.Complete();
}
// Demonstrates the consumption end of the producer and consumer pattern.
private static async Task<int> ConsumeAsync(ISourceBlock<KeyValuePair<string, string>> source)
{
// Initialize a counter to track the number of bytes that are processed.
var line = 0;
// Read from the source buffer until the source buffer has no
// available output data.
while (await source.OutputAvailableAsync())
{
var data = source.Receive();
Console.WriteLine(line + " Data received: " + data);
line++;
// Increment the count of bytes received.
// bytesProcessed += data.Length;
}
return line;
}
public static void SetUp(string targetAccount, bool headless, bool firefoxProfile)
{
var buffer = new BufferBlock<KeyValuePair<string, string>>();
Console.WriteLine("Buffer block creation has no issues");
// Start the consumer. The Consume method runs asynchronously.
var consumer = ConsumeAsync(buffer);
Console.WriteLine("Creating consumer has no issues");
// Post source data to the dataflow block.
Produce(buffer);
Console.WriteLine("Running producer has no issues");
// Wait for the consumer to process all data.
consumer.Wait();
Console.WriteLine("Waiting for consumer to finish has no issues");
// Print the count of bytes processed to the console.
Console.WriteLine("Processed {0} bytes.", consumer.Result);
}
In the example a console app is used. They use .wait to make sure the console app does not quit but in your case you should probably await it because .wait is blocking. But please share your actual code. As you might imagine it is kind of hard for us to tell what is going in if you don't post your code
以防其他人像我一样被卡住,按照@PeterBons 的建议将 "consumer.Wait()" 更改为 "await consumer" 就是答案。在我的例子中,它仍然有点古怪,但完整的功能确实有效,只是在幕后比我预期的要多一些。
我正在尝试制作一个为用户收集数据并下载的桌面应用程序。我之前使用的设置相当糟糕,一旦找到数据就调用异步下载,但我想转移到 producer/consumer 设置,因为它确实清理了我的很多代码并减少了我必须传递的方法参数的数量。
我用这个作为例子来关闭 (https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/how-to-implement-a-producer-consumer-dataflow-pattern) 并且效果很好。但是,我的应用程序也有一个 UI。这不是一个 UI 需要在程序执行它的时候工作,UI 基本上只是设置参数。我很高兴它被锁定了。它应该是。但是当我将项目(从那个link)移动到缓冲区的设置和 consumer.Wait() 到一个方法中时,当 UI 的按钮被点击时调用(运行程序),消费者从不行动。
通过日志记录,并仅使用 link 中几乎没有修改的版本,制作人将准确无误地提供我所期望的内容。但它永远不会超过 consumer.Wait()。它只会坐在那里。具体来说,它永远不会超过 "while (await source.OutputAvailableAsync()){"。它只是永远等待,而我可以保证通过 target.Post().
正确发送项目我猜测这可能与没有足够的可用线程或其他原因有关?就像消费者饿死一样?我不确定。我所能找到的都是想要交互式 UI 的人,而我绝对不需要。但似乎我的 UI 和消费者在竞争。如果我从 main 方法中删除 window,而只是从该 Microsoft 文档中放置 main class,则完全没有问题。我只是不知道如何过去。
编辑:我的代码,虽然在我尝试解决这个问题时非常混乱,但在将其切换回长期解决方案之前。
private static void Produce(ITargetBlock<KeyValuePair<string, string>> target)
{
// In a loop, fill a buffer with random data and
// post the buffer to the target block.
for (var i = 0; i < 100; i++)
{
// Create an array to hold random byte data.
var buffer = new KeyValuePair<string, string>(DateTime.Now.ToString("yyyy-M-d") + " profile",
"http://www.orseu-concours.com/451-615-thickbox/selor-test-de-raisonnement-abstrait-niveau-a.jpg");
// Post the result to the message block.
target.Post(buffer);
Console.WriteLine(buffer);
}
// Set the target to the completed state to signal to the consumer
// that no more data will be available.
target.Complete();
}
// Demonstrates the consumption end of the producer and consumer pattern.
private static async Task<int> ConsumeAsync(ISourceBlock<KeyValuePair<string, string>> source)
{
// Initialize a counter to track the number of bytes that are processed.
var line = 0;
// Read from the source buffer until the source buffer has no
// available output data.
while (await source.OutputAvailableAsync())
{
var data = source.Receive();
Console.WriteLine(line + " Data received: " + data);
line++;
// Increment the count of bytes received.
// bytesProcessed += data.Length;
}
return line;
}
public static void SetUp(string targetAccount, bool headless, bool firefoxProfile)
{
var buffer = new BufferBlock<KeyValuePair<string, string>>();
Console.WriteLine("Buffer block creation has no issues");
// Start the consumer. The Consume method runs asynchronously.
var consumer = ConsumeAsync(buffer);
Console.WriteLine("Creating consumer has no issues");
// Post source data to the dataflow block.
Produce(buffer);
Console.WriteLine("Running producer has no issues");
// Wait for the consumer to process all data.
consumer.Wait();
Console.WriteLine("Waiting for consumer to finish has no issues");
// Print the count of bytes processed to the console.
Console.WriteLine("Processed {0} bytes.", consumer.Result);
}
In the example a console app is used. They use .wait to make sure the console app does not quit but in your case you should probably await it because .wait is blocking. But please share your actual code. As you might imagine it is kind of hard for us to tell what is going in if you don't post your code
以防其他人像我一样被卡住,按照@PeterBons 的建议将 "consumer.Wait()" 更改为 "await consumer" 就是答案。在我的例子中,它仍然有点古怪,但完整的功能确实有效,只是在幕后比我预期的要多一些。