c# - Task.WaitAll not waiting on other async methods -
i'm asynchronously retrieving rss articles portable class library uses microsoft.bcl library (which doesn't have task.whenall). each article has url rss comments need asynchronously retrieve well.
the code below library. call getarticles() not return of creates list of tasks call getcomments() asynchronously comments.
i've tried using task.waitall in getarticles wait comments not block thread. appreciated.
private const string articlesuri = ""; public async task<list<articlebrief>> getarticles() { var results = new list<articlebrief>(); try { var wfw = xnamespace.get("http://wellformedweb.org/commentapi/"); var media = xnamespace.get("http://search.yahoo.com/mrss/"); var dc = xnamespace.get("http://purl.org/dc/elements/1.1/"); var t = await webhttprequestasync(articlesuri); stringreader stringreader = new stringreader(t); using (var xmlreader = system.xml.xmlreader.create(stringreader)) { var doc = system.xml.linq.xdocument.load(xmlreader); results = (from e in doc.element("rss").element("channel").elements("item") select new articlebrief() { title = e.element("title").value, description = e.element("description").value, published = convert.todatetime(e.element("pubdate").value), url = e.element("link").value, commenturi = e.element(wfw + "commentrss").value, thumbnailuri = e.element(media + "thumbnail").firstattribute.value, categories = getcategoryelements(e.elements("category")), creator = e.element(dc + "creator").value }).tolist(); } var tasks = new queue<task>(); foreach (var result in results) { tasks.enqueue( task.factory.startnew(async ()=> { result.comments = await getcomments(result.commenturi); } )); } task.waitall(tasks.toarray()); } catch (exception ex) { // should other // logging here. pass off // exception callback on ui throw ex; } return results; } public async task<list<comment>> getcomments(string uri) { var results = new list<comment>(); try { var wfw = xnamespace.get("http://wellformedweb.org/commentapi/"); var media = xnamespace.get("http://search.yahoo.com/mrss/"); var dc = xnamespace.get("http://purl.org/dc/elements/1.1/"); var t = await webhttprequestasync(uri); stringreader stringreader = new stringreader(t); using (var xmlreader = system.xml.xmlreader.create(stringreader)) { var doc = system.xml.linq.xdocument.load(xmlreader); results = (from e in doc.element("rss").element("channel").elements("item") select new comment() { description = e.element("description").value, published = convert.todatetime(e.element("pubdate").value), url = e.element("link").value, creator = e.element(dc + "creator").value }).tolist(); } } catch (exception ex) { // should other // logging here. pass off // exception callback on ui throw ex; } return results; } private static async task<string> webhttprequestasync(string url) { //todo: getting var request = webrequest.create(url); request.method = "get"; var response = await request.getresponseasync(); return readstreamfromresponse(response); } private static string readstreamfromresponse(webresponse response) { using (stream responsestream = response.getresponsestream()) using (streamreader sr = new streamreader(responsestream)) { string strcontent = sr.readtoend(); return strcontent; } } private list<string> getcategoryelements(ienumerable<xelement> categories) { var listofcategories = new list<string>(); foreach (var category in categories) { listofcategories.add(category.value); } return listofcategories; }
updated code solution, added .unwrap() on enqueue method:
var tasks = new queue<task>(); foreach (var result in results) { tasks.enqueue( task.factory.startnew(async ()=> { result.comments = await getcomments(result.commenturi); } ).unwrap()); } task.waitall(tasks.toarray());
it waiting appropriately. problem creating task
creates task (i.e. startnew
returning task<task>
, waiting on outer task
completes rather (it completes before inner task complete)).
the questions be:
- do want inner task?
- if yes, can use
task.unwrap
proxy task represents completion of both inner , outertask
, use wait on. - if no, remove use of
async
/await
in startnew there not inner task (i think prefered, it's not clear why need inner task).
- if yes, can use
- do need synchronous
wait
on asynchronous task? read of stephen cleary's blog: http://blog.stephencleary.com/2012/02/async-unit-tests-part-1-wrong-way.html
as aside, if not using c# 5, watch out closing on foreach variable result
see
Comments
Post a Comment