Sono d'accordo sia con Marc e Stephen (Cleary).
(A proposito, ho iniziato a scrivere questo come commento alla risposta di Stephen, ma si è rivelato troppo lungo: fatemi sapere se è OK scrivere come risposta o no, e sentitevi liberi di prendere le cose da esso e aggiungilo alla risposta di Stephen, nello spirito di "fornire la migliore risposta").
In realtà "dipende": come ha detto Marc, è importante sapere come DoSomethingAsync è asincrono. Siamo tutti d'accordo che non ha senso avere il metodo "sync" chiama il metodo "async" e "wait": questo può essere fatto nel codice utente. L'unico vantaggio di avere un metodo separato è quello di ottenere guadagni di prestazioni effettive, di avere un'implementazione che è, sotto la cappa, diversa e adattata allo scenario sincrono. Questo è particolarmente vero se il metodo "asincrono" sta creando un thread (o lo prende da un threadpool): si finisce con qualcosa che sotto utilizza due "control flow", mentre "promising" con i suoi look sincroni da eseguire nel contesto dei chiamanti. Questo potrebbe anche avere problemi di concorrenza, a seconda dell'implementazione.
Anche in altri casi, come l'I/O intensivo menzionato dall'OP, può valere la pena di avere due diverse implementazioni.La maggior parte dei sistemi operativi (Windows di sicuro) hanno meccanismi I/O diversi su misura per i due scenari: ad esempio, l'esecuzione asincrona e l'operazione I/O trae grandi vantaggi dai meccanismi del livello OS come le porte di completamento I/O, che aggiungono un po ' overhead (non significativo, ma non nullo) nel kernel (dopotutto, devono fare contabilità, distribuzione, ecc.) e un'implementazione più diretta per le operazioni sincrone. La complessità del codice varia molto, specialmente nelle funzioni in cui vengono eseguite/coordinate più operazioni.
Cosa farei è:
- hanno alcuni esempi/prova per utilizzo tipico e scenari
- vedere quale variante API utilizzata, dove e misura. Misura anche la differenza di prestazioni tra una variante "sincro puro" e "sincronizzazione". (non per l'intera API, ma per alcuni casi tipici selezionati)
- in base alla misurazione, decidere se vale il costo aggiunto.
Questo principalmente perché due obiettivi sono in qualche modo in contrasto l'uno con l'altro. Se si desidera un codice gestibile, la scelta più ovvia è implementare la sincronizzazione in termini di asincrono/attesa (o viceversa) (o, meglio ancora, fornire solo la variante asincrona e lasciare che l'utente "attenda"); se vuoi prestazioni devi implementare le due funzioni in modo diverso, per sfruttare diversi meccanismi sottostanti (dal framework o dal sistema operativo). Penso che non dovrebbe fare la differenza da un punto di vista del test unitario su come implementare effettivamente la tua API.
fonte
2013-02-21 10:42:25
Domanda importante: come è implementata la parte asincrona di 'DoSomethingAsync'? Questo è importante perché se questo sta creando un 'Task' e un thread di lavoro, la risposta potrebbe essere molto diversa, ad esempio, se si sta utilizzando un'API eventing esterna. Nello specifico, non ha senso avere il metodo "sync" chiama il metodo "async" e "wait", se il metodo "async" sta prendendo una discussione: sarebbe meglio fare il lavoro direttamente. Tuttavia, questo cambia per altri significati di "async" (non tutti "async" significa "thread") –
@MarcGravell, sto cercando di spiegare meglio (e non è semplice a causa dell'inglese non è la mia lingua principale). Ho "operazione XYZ" che esegue intensi I/O. Voglio esporlo in una libreria con due metodi: uno che ritorna quasi immediatamente usando un pattern asincrono (come descritto in _MS Pattern asincrono basato su Task doc_) e uno che esegue synchronous. Qual è il più ** efficiente **/** mantenibile **/** unit-test abilitato ** in questo modo. Un metodo privato esposto con un wrapper async pubblico e un altro wrapper di sincronizzazione, ad esempio? Se sì, come sono fatti questi metodi? – jay
"efficiente" e "gestibile" non sono la stessa cosa e spesso non sono d'accordo l'uno con l'altro. E ancora: dipende tutto da come sta funzionando il tuo codice "asincrono". Se questo è un codice procedurale/lineare che stai semplicemente eseguendo su un thread separato, francamente non ha senso esporrlo tramite "async". Se quel codice è completamente asincrono, allora potrebbe essere meglio avere 2 implementazioni completamente separate, se si vuole "efficiente" come obiettivo. Ci dispiace, ma questa domanda è estremamente limitata al contesto e non hai dato molto contesto. –