c# - async & await - dealing with multiple calls to same method - locking/waiting on each other? -
i had complex task/lock based mess performing 'long' data operation, , i'm trying replace async/await. i'm new async await, i'm worried i'm making big mistakes.
to simplify things, ui has few pages depend on same data. now, need data once. cache it, , further calls grab cache "cacheddataobjects" rather doing long call every time.
like (semi-pseudocode):
private dictionary<guid,list<data>> cacheddataobjects; public async task<list<data>> getdata(guid id) { list<data> data = null; //see if have cached cacheddataobjects.trygetvalue(id, out data); if (data == null) { if (connectedtoserver) { data = new list<data>(); await task.run(() => { try { //long data call data = service.getkpi(id); } catch (exception e) { //deal errors (passes action if resolved) promptforconnection(new task(async () => { data = await getdata(id); }), e); } }); } cacheddataobjects.add(id, data); } return data; }
however, nature of asynchronous calls, method get's called 2 pages when triggered.
as result, there's exception - item id has been added dictionary. if patched problem, underlying issue still there. data objects different versions, i'm doing 2 network calls should have 1 etc.
previously, 'hacked' solution encapsulating whole method in lock statement - thereby allowing single call it. data loading being done in background workers, first did call, , once had finished others unlocked perform quick grab.
but can't use lock in asynchronous method, , solution didn't feel anyway.
is there way asynchronous methods 'wait' on other asynchronous calls finish?
your problem you're await
ing task before adding dictionary. in case, you'll want add task dictionary, next page calling method same task:
public task<list<data>> getdata(guid id) { task<list<data>> task = null; cacheddataobjects.trygetvalue(id, out task); if (task == null) { if (connectedtoserver) { task = task.run(() => { try { //long data call return service.getkpi(id); } catch (exception e) { //deal errors } }); } dataobjects.add(id, task); } return task; }
this cache task. however, if //deal errors
propagates exceptions, cache exception well.
to avoid this, can use more complex code, or can adopt asynclazy<t>
type:
private readonly concurrentdictionary<guid, asynclazy<list<data>>> cacheddataobjects; public task<list<data>> getdata(guid id) { var lazy = cacheddataobjects.getoradd(id, id => new asynclazy<list<data>>(() => task.run(() => { try { return service.getkpi(id); } catch (exception e) { //deal errors throw; } }, asynclazyflags.retryonfailure | asynclazyflags.executeoncallingthread))); return lazy.task; }
Comments
Post a Comment