c# - Multiple parallel awaitable tasks -
i'm experimenting ways improve performance in our asp.net applications. 1 of things i'm looking @ using parallelism , making operations async try reduce processing time , improve throughput. started mocking frequently, issue multiple database retrievals render page.
public actionresult index() { var dal = new dal(); var cases = new list<case>(); cases.addrange( dal.getassignedcases() ); cases.addrange( dal.getnewcases() ); return view( "cases", cases ); } the 2 dal methods use thread.sleep(2000) simulate query , return collection of hard-coded objects. run apache bench using ab -c 1 -n 1 , takes 4 seconds. first attempt try improve was:
public actionresult index() { var dal = new dal(); var assignedcases = task.factory.startnew( () => dal.getassignedcases() ); var newcases = task.factory.startnew( () => dal.getnewcases() ); ienumerable<case>[] allcases = task.whenall( assignedcases, newcases ).result; return view( "cases", allcases.selectmany( c => c ) ); } when run using same ab command shows 2 seconds, makes sense because i'm running 2 tasks each of takes 2 seconds they're running in parallel.
when change benchmark 10 concurrent requests (i.e. ab -n 10 -c 10) following.
fulfilled original parallel 50% 4014 2038 66% 4015 2039 75% 4017 4011 the rest of numbers 100% similar in both columns.
i'm assuming i'm running here thread pool contention. 2/3 of requests fulfilled , after stuff sitting around waiting threads service requests. think maybe if added async mix more requests being served more quickly. that's start having problems , don't know if problem way i'm simulating long-running queries or way i'm using language feature or if i'm on wrong track , light @ end of tunnel on-coming train. :-)
first thing did create dalasync. in dalasync replaced thread.sleep(2000) await task.delay(2000), marked each method async keyword , changed return type ienumerable<case> task<ienumerable<case>>. wrote new controller method pieced information i've read in half-dozen blog posts , msdn articles.
public async task<actionresult> index() { var dal = new dalasync(); var assignedcases = dal.getassignedcasesasync(); var newcases = dal.getnewcasesasync(); var allcases = await task.whenall( assignedcases, newcases ); return view( "cases", allcases.selectmany( c => c ) ); } when run using ab never finishes, 1 request ends timing out. tried following variation, works returns numbers identical original version (which sort of makes sense, because seems i'm serializing queries again).
var assignedcases = await dal.getassignedcasesasync(); var newcases = await dal.getnewcasesasync(); var allcases = new list<case>( assignedcases ); allcases.addrange( newcases ); what i'd have happen is:
- run 2 queries in parallel
- when controller waiting dal methods respond frees thread , lets other requests execute.
your first code sample should work, eyes appears bit strange. task.whenall introduced non-blocking operation, i.e. use await task.whenall(mytasks). using .result, turning blocking operation, not feel entirely natural used way.
i think after task.waitall(params task[]) designed blocking operation.
your second code sample however, looks near perfect , go for. implementing asynchronous code throughout code-base makes cleaner implementation.
Comments
Post a Comment