[英]await not blocking until Task finishes
I am trying to block RequestHandler.ParseAll()
with await ConsumerTask;
我正在尝试使用
await ConsumerTask;
来阻止RequestHandler.ParseAll()
await ConsumerTask;
, but when i set a breakpoint there, i ALWAYS get the "Done..." output first... and then Parse2()
fails with a NullReferenceException. ,但是当我在那里设置断点时,我总是首先获得“ Done ...”输出……然后
Parse2()
失败,并显示NullReferenceException。 (thats my guess: "the GC starts cleaning up because _handler
got out of scope") (这就是我的猜测:“由于
_handler
超出范围,GC开始清理”)
Anyway, I can't figure out why that happens. 无论如何,我不知道为什么会这样。
class MainClass
{
public async void DoWork()
{
RequestHandler _handler = new RequestHandler();
string[] mUrls;
/* fill mUrls here with values */
await Task.Run(() => _handler.ParseSpecific(mUrls));
Console.WriteLine("Done...");
}
}
static class Parser
{
public static async Task<IEnumerable<string>> QueryWebPage(string url) { /*Query the url*/ }
public static async Task Parse1(Query query)
{
Parallel.ForEach(/*Process data here*/);
}
public static async Task Parse2(Query query)
{
foreach(string line in query.WebPage)
/* Here i get a NullReference exception because query.WebPage == null */
}
}
sealed class RequestHandler
{
private BlockingCollection<Query> Queue;
private Task ConsumerTask = Task.Run(() => /* call consume() for each elem in the queue*/);
private async void Consume(Query obj)
{
await (obj.BoolField ? Parser.Parse1(obj) : Parser.Parse2(obj));
}
public async void ParseSpecific(string[] urls)
{
foreach(string v in urls)
Queue.Add(new Query(await QueryWebPage(v), BoolField: false));
Queue.CompleteAdding();
await ConsumerTask;
await ParseAll(true);
}
private async Task ParseAll(bool onlySome)
{
ReInit();
Parallel.ForEach(mCollection, v => Queue.Add(new Query(url, BoolField:false)));
Queue.CompleteAdding();
await ConsumerTask;
/* Process stuff further */
}
}
struct Query
{
public readonly string[] WebPage;
public readonly bool BoolField;
public Query(uint e, IEnumerable<string> page, bool b) : this()
{
Webpage = page.ToArray();
BoolField = b;
}
}
CodesInChaos has spotted the problem in comments. CodesInChaos在注释中发现了问题。 It stems from having async methods returning
void
, which you should almost never do - it means you've got no way to track them. 它源于异步方法返回
void
,您几乎不应该这样做-这意味着您无法跟踪它们。
Instead, if your async methods don't have any actual value to return, you should just make them return Task
. 相反,如果您的异步方法没有要返回的实际值,则应使它们返回
Task
。
What's happening is that ParseSpecific
is only running synchronously until the first await QueryWebPage(v)
that doesn't complete immediately. 发生的情况是,
ParseSpecific
仅同步运行,直到第一个await QueryWebPage(v)
操作没有立即完成。 It's then returning... so the task started here: 然后返回...所以任务从这里开始:
await Task.Run(() => _handler.ParseSpecific(mUrls));
... completes immediately, and "Done" gets printed. ...立即完成,并打印“完成”。
Once you've made all your async methods return Task
, you can await them. 一旦所有异步方法都返回
Task
,就可以等待它们。 You also won't need Task.Run
at all. 您也完全不需要
Task.Run
。 So you'd have: 因此,您将拥有:
public async void DoWork()
{
RequestHandler _handler = new RequestHandler();
string[] mUrls;
await _handler.ParseSpecific(mUrls);
Console.WriteLine("Done...");
}
... ...
public async TaskParseSpecific(string[] urls)
{
foreach(string v in urls)
{
// Refactored for readability, although I'm not sure it really
// makes sense now that it's clearer! Are you sure this is what
// you want?
var page = await QueryWebPage(v);
Queue.Add(new Query(page, false);
}
Queue.CompleteAdding();
await ConsumerTask;
await ParseAll(true);
}
Your Reinit
method also needs changing, as currently the ConsumerTask
will basically complete almost immediately, as Consume
will return immediately as it's another async method returning void. 您的
Reinit
方法也需要更改,因为当前ConsumerTask
基本上会立即完成,因为Consume
将立即返回,因为这是另一个返回void的异步方法。
To be honest, what you've got looks very complex, without a proper understanding of async/await. 老实说,您所拥有的内容看起来非常复杂,没有对async / await的正确理解。 I would read up more on async/await and then probably start from scratch.
我会在async / await上阅读更多内容,然后可能从头开始。 I strongly suspect you can make this much, much simpler.
我强烈怀疑您可以简化很多事情。 You might also want to read up on TPL Dataflow which is designed to make producer/consumer scenarios simpler.
您可能还想阅读TPL Dataflow ,它旨在简化生产者/消费者场景。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.