c# - Best solution for async chicken and egg story -
i have been applying async best practices libraries. means:
- only use async when it's async (libraries shouldn't lie)
- define synchronous method if , if have faster synchronous method won’t dead lock.
- postfix async methods async
i worked on library synchronous nature. means has sync methods. if user wants run work on separate thread ui thread, can using task.factory
(responsibility of caller).
however, inside handler / method / extensibility point, want show user message box. async method (for example, winrt showdialogasync
). gives following options:
a. move async (so have option use await in our handlers , don't block anything).
public async task mymethodasync() { await _messageservice.showasync(); }
the advantage users can add async methods without having use .wait(). downside lying library (it's not async).
i have considered making everything async, don't think that's idea either. make libraries lie prepare them in case need it. remember making async out of box has (small) performance impact well.
b. inside handler requires user input, call .wait()
public void mymethod() { _messageservice.showasync().wait(); }
the advantage allow use async code inside sync methods. but... never callable ui-thread because _messageservice dispatches ui thread (but cannot because it's still waiting method, resulting in deadlock). method will work when used inside task.factory.run block (but responsibility end-user):
await task.factory.run(() => mymethod());
the question
i feel both have pros , cons, choose? let library lie (a) or allow method called background thread (b)? or maybe there other options i've overseen.
if go a, means have bump major version every time (because it's breaking change) whenever user requests convert method async signature method.
define synchronous method if , if have faster synchronous method won’t dead lock.
i'd "define synchronous method if have synchronous work do". doesn't matter how fast is. burden on caller determine if it's slow , need use task.run
.
however, inside handler / method / extensibility point
if observer kind of extensibility, consider using events or observables.
however, sounds want more of strategy kind of extensibility, invoking code must wait and/or change behavior based on result of callback.
i have considered making async, don't think that's idea either.
async way guideline, not strict command. applies in 99% case, 1 of exceptions. try not make library async sake of possibly-async strategy pattern; i'd investigate other extension possibilities first. there valid argument making library async, if view strategy callback dependency (the library async because dependency (possibly) async).
as you've discovered, there's no clean way sync-over-async. there few different hacks (such blocking background thread), you'll first need decide whether need call library ui thread.
if do, there's 2 options: make library async, or use nested message loop. avoid nested message loops, in libraries; i'm mentioning sake of completeness.
if can impose on user requirement call library non-ui thread, can apply other hacks. e.g., blocking background thread.
there's not easy solution, sorry.
as far me personally... if library needs async strategy, lean towards making library async. depend on kind of library is, whether there backwards-compatibility issues, etc. , first thing i'd different kind of extensibility point.
Comments
Post a Comment