Cómo y cuándo usar `async` y` await`

Desde mi punto de vista, una de las cosas principales que se async y await es hacer que el código sea fácil de escribir y de leer, pero ¿está utilizándolo igual que para engendrar hilos de fondo para realizar una lógica de larga duración?

Actualmente estoy probando el ejemplo más básico. He agregado algunos comentarios en línea. ¿Puedes aclararlo por mí?

 // I don't understand why this method must be marked as `async`. private async void button1_Click(object sender, EventArgs e) { Task access = DoSomethingAsync(); // task independent stuff here // this line is reached after the 5 seconds sleep from // DoSomethingAsync() method. Shouldn't it be reached immediately? int a = 1; // from my understanding the waiting should be done here. int x = await access; } async Task DoSomethingAsync() { // is this executed on a background thread? System.Threading.Thread.Sleep(5000); return 1; } 

Cuando se usa async y se await el comstackdor genera una máquina de estado en el fondo.

Aquí hay un ejemplo en el que espero poder explicar algunos de los detalles de alto nivel que están sucediendo:

 public async Task MyMethodAsync() { Task longRunningTask = LongRunningOperationAsync(); // independent work which doesn't need the result of LongRunningOperationAsync can be done here //and now we call await on the task int result = await longRunningTask; //use the result Console.WriteLine(result); } public async Task LongRunningOperationAsync() // assume we return an int from this long running operation { await Task.Delay(1000); // 1 second delay return 1; } 

OK, entonces, ¿qué pasa aquí?

  1. Task longRunningTask = LongRunningOperationAsync(); comienza a ejecutar LongRunningOperation

  2. El trabajo independiente se lleva a cabo supongamos que el hilo principal (ID del hilo = 1) luego await longRunningTask sea ​​alcanzado.

    Ahora, si longRunningTask no ha finalizado y todavía se está ejecutando, MyMethodAsync() volverá a su método de llamada, por lo que el hilo principal no se bloquea. Cuando longRunningTask se realiza, un hilo del ThreadPool (puede ser cualquier hilo) volverá a MyMethodAsync() en su contexto anterior y continuará la ejecución (en este caso, imprimirá el resultado en la consola).

Un segundo caso sería que longRunningTask ya ha finalizado su ejecución y el resultado está disponible. Al llegar a la await longRunningTask , ya tenemos el resultado, por lo que el código continuará ejecutándose en el mismo hilo. (en este caso, imprimir el resultado a la consola). Por supuesto, este no es el caso para el ejemplo anterior, donde hay un Task.Delay(1000) involucrado.

Además de las otras respuestas, eche un vistazo a await (C # Reference)

y más específicamente en el ejemplo incluido, explica su situación un poco

El siguiente ejemplo de Windows Forms ilustra el uso de await en un método asíncrono, WaitAsynchronouslyAsync. Contraste el comportamiento de ese método con el comportamiento de WaitSynchronously. Sin un operador aguardado aplicado a una tarea, WaitSynchronously se ejecuta sincrónicamente a pesar del uso del modificador asíncrono en su definición y una llamada a Thread.Sleep en su cuerpo.

 private async void button1_Click(object sender, EventArgs e) { // Call the method that runs asynchronously. string result = await WaitAsynchronouslyAsync(); // Call the method that runs synchronously. //string result = await WaitSynchronously (); // Display the result. textBox1.Text += result; } // The following method runs asynchronously. The UI thread is not // blocked during the delay. You can move or resize the Form1 window // while Task.Delay is running. public async Task WaitAsynchronouslyAsync() { await Task.Delay(10000); return "Finished"; } // The following method runs synchronously, despite the use of async. // You cannot move or resize the Form1 window while Thread.Sleep // is running because the UI thread is blocked. public async Task WaitSynchronously() { // Add a using directive for System.Threading. Thread.Sleep(10000); return "Finished"; } 

Desde mi punto de vista, una de las cosas principales que se sincronizan y aguardan es hacer que el código sea fácil de escribir y leer.

Deben hacer que el código asíncrono sea fácil de escribir y leer, sí.

¿Es lo mismo que engendrar hilos de fondo para realizar una lógica de larga duración?

De ningún modo.

// No entiendo por qué este método debe marcarse como “async”.

La palabra clave async habilita la palabra clave await . Por lo tanto, cualquier método que use await debe marcarse como async .

// esta línea se alcanza después de los 5 segundos de suspensión del método DoSomethingAsync (). ¿No debería ser alcanzado inmediatamente?

No, porque los métodos async no se ejecutan en otro subproceso de manera predeterminada.

// ¿esto se ejecuta en un hilo de fondo?

No.


Puede encontrar útil mi introducción async / await . Los documentos oficiales de MSDN también son inusualmente buenos (especialmente la sección TAP ), y el equipo de async una excelente pregunta frecuente .

Explicación

Aquí hay un ejemplo rápido de async / await en un nivel alto. Hay muchos más detalles para considerar más allá de esto.

Nota: Task.Delay(1000) simula hacer trabajo durante 1 segundo. Creo que es mejor pensar en esto como esperar una respuesta de un recurso externo. Dado que nuestro código está esperando una respuesta, el sistema puede establecer la tarea de ejecución a un lado y volver a ella una vez que haya finalizado. Mientras tanto, puede hacer otro trabajo en ese hilo.

En el siguiente ejemplo, el primer bloque está haciendo exactamente eso. Inicia todas las tareas de inmediato (las líneas Task.Delay ) y las pone a un lado. El código se detendrá en await a línea hasta que se complete el retraso de 1 segundo antes de pasar a la siguiente línea. Como b , c , d , y e comenzaron a ejecutarse casi a la misma hora que a (debido a la falta de la espera), deberían terminar más o menos al mismo tiempo en este caso.

En el siguiente ejemplo, el segundo bloque inicia una tarea y espera que termine (eso es lo que await ) antes de comenzar las tareas siguientes. Cada iteración de esto toma 1 segundo. La await está pausando el progtwig y esperando el resultado antes de continuar. Esta es la principal diferencia entre el primer y el segundo bloque.

Ejemplo

 Console.WriteLine(DateTime.Now); // This block takes 1 second to run because all // 5 tasks are running simultaneously { var a = Task.Delay(1000); var b = Task.Delay(1000); var c = Task.Delay(1000); var d = Task.Delay(1000); var e = Task.Delay(1000); await a; await b; await c; await d; await e; } Console.WriteLine(DateTime.Now); // This block takes 5 seconds to run because each "await" // pauses the program until the task finishes { await Task.Delay(1000); await Task.Delay(1000); await Task.Delay(1000); await Task.Delay(1000); await Task.Delay(1000); } Console.WriteLine(DateTime.Now); 

SALIDA:

 5/24/2017 2:22:50 PM 5/24/2017 2:22:51 PM (First block took 1 second) 5/24/2017 2:22:56 PM (Second block took 5 seconds) 

Información adicional sobre SynchronizationContext

Nota: Aquí es donde las cosas se ponen un poco confusas, así que si me equivoco en algo, por favor corrígeme y actualizaré la respuesta. Es importante tener una comprensión básica de cómo funciona esto, pero puede salir adelante sin ser un experto siempre que nunca use ConfigureAwait(false) , aunque es probable que pierda alguna oportunidad de optimización, supongo.

Hay un aspecto de esto que hace que el concepto async / await sea algo más difícil de captar. Ese es el hecho de que en este ejemplo, todo esto sucede en el mismo hilo (o al menos lo que parece ser el mismo hilo en lo que respecta a SynchronizationContext). De forma predeterminada, await restablecerá el contexto de sincronización del subproceso original en el que se estaba ejecutando. Por ejemplo, en ASP.NET tiene un HttpContext que está vinculado a un hilo cuando entra una solicitud. Este contexto contiene cosas específicas para la solicitud Http original, como el objeto Request original que tiene cosas como lenguaje, dirección IP, encabezados, etc. Si cambia los hilos a la mitad del procesamiento de algo, podría terminar tratando de extraer información de este objeto en un HttpContext diferente que podría ser desastroso. Si sabe que no usará el contexto para nada, puede elegir “no importarle”. Esto básicamente permite que su código se ejecute en un hilo separado sin traer el contexto alrededor.

¿Cómo lo logras? Por defecto, el await a; En realidad, el código es suponer que DESEA capturar y restaurar el contexto:

 await a; //Same as the line below await a.ConfigureAwait(true); 

Si desea permitir que el código principal continúe en un nuevo hilo sin el contexto original, simplemente use falso en lugar de verdadero para que sepa que no necesita restaurar el contexto.

 await a.ConfigureAwait(false); 

Una vez que el progtwig finalice en pausa, continuará potencialmente en un hilo completamente diferente con un contexto diferente. De aquí surgiría la mejora del rendimiento: podría continuar en cualquier hilo disponible sin tener que restaurar el contexto original con el que comenzó.

¿Esto es confuso? ¡Demonios si! ¿Puedes averiguarlo? ¡Probablemente! Una vez que tenga una comprensión de los conceptos, continúe con las explicaciones de Stephen Cleary, que tienden a orientarse más hacia alguien con una comprensión técnica de async / await ya.

Mostrando las explicaciones anteriores en acción en un progtwig de consola simple –

 class Program { static void Main(string[] args) { TestAsyncAwaitMethods(); Console.WriteLine("Press any key to exit..."); Console.ReadLine(); } public async static void TestAsyncAwaitMethods() { await LongRunningMethod(); } public static async Task LongRunningMethod() { Console.WriteLine("Starting Long Running method..."); await Task.Delay(5000); Console.WriteLine("End Long Running method..."); return 1; } } 

Y la salida es:

 Starting Long Running method... Press any key to exit... End Long Running method... 

Así,

  1. Principal inicia el método de larga ejecución a través de TestAsyncAwaitMethods. Eso vuelve inmediatamente sin detener el hilo actual e inmediatamente vemos el mensaje ‘Presione cualquier tecla para salir’
  2. Mientras tanto, LongRunningMethod se ejecuta en segundo plano. Una vez que se completa, otro hilo de Threadpool toma este contexto y muestra el mensaje final

Por lo tanto, no hilo está bloqueado.

Creo que has elegido un mal ejemplo con System.Threading.Thread.Sleep

El punto de una tarea async es permitir que se ejecute en segundo plano sin bloquear el hilo principal, como hacer un DownloadFileAsync

System.Threading.Thread.Sleep no es algo que se “está haciendo”, simplemente duerme y, por lo tanto, se llega a la siguiente línea después de 5 segundos …

Lee este artículo, creo que es una gran explicación de async y await concepto: http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx

Aquí hay un progtwig de consola rápido para dejar en claro a los que siguen. El método “TaskToDo” es su método de larga ejecución que desea sincronizar. Hacer que funcione Async se realiza mediante el método TestAsync. El método de bucles de prueba solo ejecuta las tareas de “Tarea para hacer” y las ejecuta Async. Puede ver eso en los resultados porque no se completan en el mismo orden desde la ejecución hasta la ejecución; informan al hilo de la interfaz de usuario de la consola cuando se completan. Simplista, pero creo que los ejemplos simplistas resaltan el núcleo del patrón mejor que los ejemplos más involucrados:

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace TestingAsync { class Program { static void Main(string[] args) { TestLoops(); Console.Read(); } private static async void TestLoops() { for (int i = 0; i < 100; i++) { await TestAsync(i); } } private static Task TestAsync(int i) { return Task.Run(() => TaskToDo(i)); } private async static void TaskToDo(int i) { await Task.Delay(10); Console.WriteLine(i); } } } 

Esta respuesta tiene como objective proporcionar información específica para ASP.NET.

Al utilizar async / await en el controlador MVC, es posible boost la utilización del grupo de subprocesos y lograr un rendimiento mucho mejor, como se explica en el siguiente artículo,

http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4

En las aplicaciones web que ven una gran cantidad de solicitudes concurrentes al inicio o tienen una carga de ráfagas (donde la concurrencia aumenta repentinamente), hacer que estas llamadas al servicio web sean asincrónicas boostá la capacidad de respuesta de su aplicación. Una solicitud asincrónica requiere la misma cantidad de tiempo para procesar que una solicitud síncrona. Por ejemplo, si una solicitud realiza una llamada de servicio web que requiere dos segundos para completarse, la solicitud demora dos segundos, ya sea que se realice de forma síncrona o asíncrona. Sin embargo, durante una llamada asincrónica, un hilo no está bloqueado para responder a otras solicitudes mientras espera a que se complete la primera solicitud. Por lo tanto, las solicitudes asincrónicas evitan que las colas de solicitudes crezcan y el grupo de subidas crezca cuando hay muchas solicitudes concurrentes que invocan operaciones de larga ejecución.

Para ser sincero, sigo pensando que la mejor explicación es la del futuro y las promesas en la Wikipedia: http://en.wikipedia.org/wiki/Futures_and_promises

La idea básica es que tienes un conjunto separado de subprocesos que ejecutan tareas de forma asincrónica. Cuando lo usas Sin embargo, el objeto promete que ejecutará la operación en algún momento y le dará el resultado cuando lo solicite. Esto significa que se bloqueará cuando solicite el resultado y no haya finalizado, pero se ejecutará en el grupo de subprocesos de lo contrario.

Desde allí puede optimizar cosas: algunas operaciones se pueden implementar de manera sincronizada y puede optimizar cosas como el archivo I / O y la comunicación de red al agrupar las solicitudes subsiguientes y / o reordenarlas. No estoy seguro de si esto ya está en el marco de tareas de Microsoft, pero si no fuera eso, sería una de las primeras cosas que agregaría.

En realidad, puede implementar el patrón de clasificación futuro con rendimientos en C # 4.0. Si desea saber cómo funciona exactamente, puedo recomendar este enlace que hace un trabajo decente: http://code.google.com/p/fracture/source/browse/trunk/Squared/TaskLib/ . Sin embargo, si comienza a jugar con usted mismo, notará que realmente necesita soporte de idiomas si desea hacer todas las cosas interesantes, que es exactamente lo que hizo Microsoft.

Todas las respuestas aquí usan Task.Delay () o alguna otra función incorporada asincrónica. Pero aquí está mi ejemplo que no usa ninguna de esas funciones asíncronas:

  // Starts counting to a large numbewr and then immediately displays message "i'm counting...". // Then it waits for task to finish and displays "finished, press any key". static void asyncTest () { Console.WriteLine("Started asyncTest()"); Task task = asyncTest_count(); Console.WriteLine("Started counting, please wait..."); task.Wait(); // if you comment this line you will see that message "Finished counting" will be displayed before we actually finished counting. //Console.WriteLine("Finished counting to " + task.Result.ToString()); // using task.Result seems to also call task.Wait(). Console.WriteLine("Finished counting."); Console.WriteLine("Press any key to exit program."); Console.ReadLine(); } static async Task asyncTest_count() { long k = 0; Console.WriteLine("Started asyncTest_count()"); await Task.Run(() => { long countTo = 100000000; int prevPercentDone = -1; for (long i = 0; i <= countTo; i++) { int percentDone = (int)(100 * (i / (double)countTo)); if (percentDone != prevPercentDone) { prevPercentDone = percentDone; Console.Write(percentDone.ToString() + "% "); } k = i; } }); Console.WriteLine(""); Console.WriteLine("Finished asyncTest_count()"); return k; } 

Ver este violín https://dotnetfiddle.net/VhZdLU (y mejorarlo si es posible) para ejecutar una aplicación de consola simple que muestra los usos de Tarea, Tarea.WaitAll (), asincrónica y espera a los operadores en el mismo progtwig.

Este violín debe borrar su concepto de ciclo de ejecución.

Aquí está el código de ejemplo

 using System; using System.Threading.Tasks; public class Program { public static void Main() { var a = MyMethodAsync(); //Task started for Execution and immediately goes to Line 19 of the code. Cursor will come back as soon as await operator is met Console.WriteLine("Cursor Moved to Next Line Without Waiting for MyMethodAsync() completion"); Console.WriteLine("Now Waiting for Task to be Finished"); Task.WaitAll(a); //Now Waiting Console.WriteLine("Exiting CommandLine"); } public static async Task MyMethodAsync() { Task longRunningTask = LongRunningOperation(); // independent work which doesn't need the result of LongRunningOperationAsync can be done here Console.WriteLine("Independent Works of now executes in MyMethodAsync()"); //and now we call await on the task int result = await longRunningTask; //use the result Console.WriteLine("Result of LongRunningOperation() is " + result); } public static async Task LongRunningOperation() // assume we return an int from this long running operation { Console.WriteLine("LongRunningOperation() Started"); await Task.Delay(2000); // 2 second delay Console.WriteLine("LongRunningOperation() Finished after 2 Seconds"); return 1; } } 

Rastreo proveniente de la ventana de salida: enter image description here

 public static void Main(string[] args) { string result = DownloadContentAsync().Result; Console.ReadKey(); } // You use the async keyword to mark a method for asynchronous operations. // The "async" modifier simply starts synchronously the current thread. // What it does is enable the method to be split into multiple pieces. // The boundaries of these pieces are marked with the await keyword. public static async Task DownloadContentAsync()// By convention, the method name ends with "Async { using (HttpClient client = new HttpClient()) { // When you use the await keyword, the compiler generates the code that checks if the asynchronous operation is finished. // If it is already finished, the method continues to run synchronously. // If not completed, the state machine will connect a continuation method that must be executed WHEN the Task is completed. // Http request example. // (In this example I can set the milliseconds after "sleep=") String result = await client.GetStringAsync("http://httpstat.us/200?sleep=1000"); Console.WriteLine(result); // After completing the result response, the state machine will continue to synchronously execute the other processes. return result; } } 

La forma en que lo entiendo es que también debe haber un tercer término agregado a la mezcla: Task .

Async es solo un calificador que le pones a tu método para decir que es un método asincrónico.

Task es el regreso de la función async . Se ejecuta de forma asincrónica.

await una Tarea. Cuando la ejecución del código llega a esta línea, el control salta de vuelta al llamante de la función original que le rodea.

Si, en cambio, asigna el retorno de una función async (es decir, Task ) a una variable, cuando la ejecución del código llega a esta línea, simplemente continúa más allá de esa línea en la función circundante mientras la Task ejecuta de forma asíncrona.

¿Los usa igual que los hilos de fondo de desove para realizar una lógica de larga duración?

Este artículo MDSN: Progtwigción asincrónica con async y await (C #) lo explica explícitamente:

Las palabras clave async y await no provocan la creación de subprocesos adicionales. Los métodos asíncronos no requieren multithreading porque un método async no se ejecuta en su propio hilo. El método se ejecuta en el contexto de sincronización actual y usa el tiempo en la secuencia solo cuando el método está activo.

En el siguiente código, el método HttpClient GetByteArrayAsync devuelve una Tarea, getContentsTask. La tarea es una promesa de producir la matriz de bytes real cuando se completa la tarea. El operador await se aplica a getContentsTask para suspender la ejecución en SumPageSizesAsync hasta que se complete getContentsTask. Mientras tanto, el control se devuelve a la persona que llama de SumPageSizesAsync. Cuando getContentsTask finaliza, la expresión await se evalúa como una matriz de bytes.

 private async Task SumPageSizesAsync() { // To use the HttpClient type in desktop apps, you must include a using directive and add a // reference for the System.Net.Http namespace. HttpClient client = new HttpClient(); // . . . Task getContentsTask = client.GetByteArrayAsync(url); byte[] urlContents = await getContentsTask; // Equivalently, now that you see how it works, you can write the same thing in a single line. //byte[] urlContents = await client.GetByteArrayAsync(url); // . . . } 

En un nivel superior:

1) La palabra clave Async permite esperar y eso es todo lo que hace. La palabra clave Async no ejecuta el método en un hilo separado. El método f async inicial se ejecuta sincrónicamente hasta que se agita en una tarea que consume mucho tiempo.

2) Puede esperar en un método que devuelve Tarea o Tarea de tipo T. No puede esperar en el método de anync void.

3) En el momento en que el hilo principal se encuentra con una tarea que consume mucho tiempo o cuando se inicia el trabajo real, el hilo principal vuelve a la persona que llama del método actual.

4) Si el subproceso principal ve en una tarea que aún se está ejecutando, no espera y regresa a la persona que llama del método actual. De esta manera, la aplicación sigue siendo receptiva.

5) Aguardar al procesar la tarea, ahora se ejecutará en un subproceso separado del grupo de subprocesos.

6) Cuando se complete esta tarea de espera, todo el código debajo será ejecutado por el hilo separado

A continuación se muestra el código de muestra. Ejecútelo y verifique el ID del hilo

 using System; using System.Threading; using System.Threading.Tasks; namespace AsyncAwaitDemo { class Program { public static async void AsynchronousOperation() { Console.WriteLine("Inside AsynchronousOperation Before AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId); //Task _task = AsyncMethod(); int count = await AsyncMethod(); Console.WriteLine("Inside AsynchronousOperation After AsyncMethod Before Await, Thread Id: " + Thread.CurrentThread.ManagedThreadId); //int count = await _task; Console.WriteLine("Inside AsynchronousOperation After AsyncMethod After Await Before DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId); DependentMethod(count); Console.WriteLine("Inside AsynchronousOperation After AsyncMethod After Await After DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId); } public static async Task AsyncMethod() { Console.WriteLine("Inside AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId); int count = 0; await Task.Run(() => { Console.WriteLine("Executing a long running task which takes 10 seconds to complete, Thread Id: " + Thread.CurrentThread.ManagedThreadId); Thread.Sleep(20000); count = 10; }); Console.WriteLine("Completed AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId); return count; } public static void DependentMethod(int count) { Console.WriteLine("Inside DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId + ". Total count is " + count); } static void Main(string[] args) { Console.WriteLine("Started Main method, Thread Id: " + Thread.CurrentThread.ManagedThreadId); AsynchronousOperation(); Console.WriteLine("Completed Main method, Thread Id: " + Thread.CurrentThread.ManagedThreadId); Console.ReadKey(); } } } 

Las respuestas aquí son útiles como una guía general sobre await / async. También contienen algunos detalles sobre cómo está cableado await / async. Me gustaría compartir con ustedes algunas experiencias prácticas que deben conocer antes de usar este patrón de diseño.

El término “esperar” es literal, por lo que cualquier hilo que lo invoque esperará el resultado del método antes de continuar. En el hilo de primer plano , esto es un desastre . El subproceso en primer plano conlleva la carga de construir su aplicación, incluidas vistas, modelos de vista, animaciones iniciales y cualquier otra cosa que haya ajustado para arrancar con esos elementos. Entonces, cuando esperas el hilo de primer plano, paras la aplicación. El usuario espera y espera cuando nada parece suceder. Esto proporciona una experiencia de usuario negativa.

Sin duda puede esperar un hilo de fondo utilizando una variedad de medios:

 Device.BeginInvokeOnMainThread(async () => { await AnyAwaitableMethod(); }); // Notice that we do not await the following call, // as that would tie it to the foreground thread. try { Task.Run(async () => { await AnyAwaitableMethod(); }); } catch {} 

El código completo para estas observaciones se encuentra en https://github.com/marcusts/xamarin-forms-annoyances . Vea la solución llamada AwaitAsyncAntipattern.sln.

El sitio de GitHub también proporciona enlaces a una discusión más detallada sobre este tema.

Below is code which reads excel file by opening dialog and then uses async and wait to run asynchronous the code which reads one by one line from excel and binds to grid

  namespace EmailBillingRates { public partial class Form1 : Form { public Form1() { InitializeComponent(); lblProcessing.Text = ""; } private async void btnReadExcel_Click(object sender, EventArgs e) { string filename = OpenFileDialog(); Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application(); Microsoft.Office.Interop.Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(filename); Microsoft.Office.Interop.Excel._Worksheet xlWorksheet = xlWorkbook.Sheets[1]; Microsoft.Office.Interop.Excel.Range xlRange = xlWorksheet.UsedRange; try { Task longRunningTask = BindGrid(xlRange); int result = await longRunningTask; } catch (Exception ex) { MessageBox.Show(ex.Message.ToString()); } finally { //cleanup // GC.Collect(); //GC.WaitForPendingFinalizers(); //rule of thumb for releasing com objects: // never use two dots, all COM objects must be referenced and released individually // ex: [somthing].[something].[something] is bad //release com objects to fully kill excel process from running in the background Marshal.ReleaseComObject(xlRange); Marshal.ReleaseComObject(xlWorksheet); //close and release xlWorkbook.Close(); Marshal.ReleaseComObject(xlWorkbook); //quit and release xlApp.Quit(); Marshal.ReleaseComObject(xlApp); } } private void btnSendEmail_Click(object sender, EventArgs e) { } private string OpenFileDialog() { string filename = ""; OpenFileDialog fdlg = new OpenFileDialog(); fdlg.Title = "Excel File Dialog"; fdlg.InitialDirectory = @"c:\"; fdlg.Filter = "All files (*.*)|*.*|All files (*.*)|*.*"; fdlg.FilterIndex = 2; fdlg.RestoreDirectory = true; if (fdlg.ShowDialog() == DialogResult.OK) { filename = fdlg.FileName; } return filename; } private async Task BindGrid(Microsoft.Office.Interop.Excel.Range xlRange) { lblProcessing.Text = "Processing File.. Please wait"; int rowCount = xlRange.Rows.Count; int colCount = xlRange.Columns.Count; // dt.Column = colCount; dataGridView1.ColumnCount = colCount; dataGridView1.RowCount = rowCount; for (int i = 1; i <= rowCount; i++) { for (int j = 1; j <= colCount; j++) { //write the value to the Grid if (xlRange.Cells[i, j] != null && xlRange.Cells[i, j].Value2 != null) { await Task.Delay(1); dataGridView1.Rows[i - 1].Cells[j - 1].Value = xlRange.Cells[i, j].Value2.ToString(); } } } lblProcessing.Text = ""; return 0; } } internal class async { } 

} `