【发布时间】:2013-03-16 07:21:49
【问题描述】:
我试图用await ConsumerTask; 阻止RequestHandler.ParseAll(),但是当我在那里设置断点时,我总是首先得到“完成...”输出...然后Parse2() 失败并出现NullReferenceException。 (这是我的猜测:“GC 开始清理,因为 _handler 超出范围”)
无论如何,我无法弄清楚为什么会发生这种情况。
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;
}
}
【问题讨论】:
-
您的示例非常复杂(对于有很多没有
Async后缀的异步方法更是如此)-您可以将其减少吗? -
ParseSpecific返回其第一个await语句。你不await ParseSpecific -
@JonSkeet:我尽可能地减少它,没有试图留下任何重要的东西......但我会尝试。
-
@Nefarion:CodesInChaos 在他的评论中已经弄清楚了——我正在详细说明。
-
@CodesInChaos:我希望你不介意我基本上跳出你发现问题所在的事实 :) 很好,先生!
标签: c# asynchronous async-await