2011-02-18 12 views
12

En el mundo sincrónico, C# hace que la gestión de todas las cosas desechables realmente bastante fácil:disposición a prueba de fallos en un mundo asíncrono

using(IDisposable someDisposable=bla.bla()) 
{ 
    //do our bidding 
} 
//don't worry too much about it 

Sin embargo, cuando vamos asíncrono, ya no tenemos la comodidad del bloque using . Una de las mejores estrategias que he encontrado es la CCR iterator que nos permite usar el código asíncrono "como si fuera síncrono". Esto significa que podemos mantener nuestro bloque using en el controlador de iteradores y no quedarnos atascados en la compleja decisión de cuándo disponer y detectar todos los casos en que se requiere su eliminación.

Sin embargo, en muchos casos, invocar CCR puede parecer exagerado, y para ser honesto, aunque estoy bastante cómodo con CCR, para los no iniciados puede parecer doble holandés.

Así que mi pregunta es: ¿qué otras estrategias existen para la gestión de los propios IDisposables, cuando los objetos desechables deben persistir más allá del alcance inmediato?

+0

Buena pregunta. Solo estoy publicando este comentario para poder encontrarlo nuevamente. – MusiGenesis

+1

@MusiGenesis: ¿No tiene más sentido "preferir" la pregunta para que sea más fácil de encontrar? – Gabe

+0

@Gabe: ¿cómo se supone que debo recordar para ir a mirar mis favoritos? – MusiGenesis

Respuesta

0

Resulta que este problema también estaba en la mente de los diseñadores de idiomas.

La respuesta correcta a esta pregunta es ahora utilizar las versiones basadas Task de las API asincrónicas que se han proporcionado para casi todas las operaciones asíncronas, junto con el nuevo C# async/await palabras clave. Estos nos permiten mantener todo en el alcance durante la vida útil de las operaciones asincrónicas:

async Task<int> DoSomething() 
{ 
    using(var foo = new SomeDisposableThing()) 
    { 
     await foo.DoSomethingAsync(); 
    } 
    return 0; 
} 
1

Un enfoque consiste en hacer que todos los métodos que no puedan coexistir con el método de eliminación se bloqueen mientras se ejecutan, y verificar una cola de objetos que necesitan eliminación cuando terminan. El método de eliminación podría entonces agregarse a la cola, usar TryEnter para tratar de adquirir el bloqueo, eliminar el objeto y eliminarlo de la cola si tiene éxito, o bien dejar que el titular actual del bloqueo maneje la eliminación.

+0

¿Qué pasa con las devoluciones de llamada? El código que debe completarse antes de su eliminación puede que no se ejecute hasta que ocurra algún otro evento. –

+0

@Ben Voigt: Supongo que se sabe cuándo un artículo en particular ya no será necesario. Lo que hace que la eliminación asíncrona sea difícil no es la posibilidad de operaciones simultáneas o pendientes con el objeto que se está eliminando, sino más bien operaciones simultáneas en entidades que se verán afectadas por el desecho. Supongamos, por ejemplo, que uno tiene una base de datos que usa una sola secuencia de datos para la comunicación; a diferentes conexiones se les asignan números de identificación, y cada comando o respuesta incluye la identificación de conexión. Si se envía un comando cuando un hilo desea cerrar una conexión ... – supercat

+0

@Ben Voigt: ... el comando "cerrar" tendría que esperar. Dependiendo de las circunstancias, puede ser bueno que el Dispose espere hasta que se complete el cierre para que uno sepa si funcionó, pero si eso pudiera tomar un tiempo, podría ser mejor desechar para poner en cola el comando de cierre y regresar inmediatamente. El punto es que lo importante no son los hilos múltiples que usan el objeto de conexión, sino múltiples hilos que usan la secuencia de datos. – supercat

Cuestiones relacionadas