En ciertas ocasiones, cuando trabajamos con grandes cantidades de datos al mismo tiempo las interfaces de nuestros programas pueden quedar bloqueadas. Esto generalmente hace que el usuario pierda la paciencia y termine cerrando la aplicación con la famosa combinación CTRL+ALT+SUPR.

Para evitarlo podemos hacer uso de los hilos de toda la vida o de la API asíncrona que nos ofrece ADO.NET:

Begin/EndExecuteNonQuery

Begin/EndExecuteReader

Begin/EndExecuteXmlReader

Es muy sencillo así que voy a mostrarlo con un ejemplo en el que hago múltiples inserciones en una tabla de la base de datos.

Lo primero que haremos es crear un objeto SqlConnection y otro SqlCommand:

SqlConnection conexion = new SqlConnection(@"Data Source=.\SQLEXPRESS;AttachDbFilename=C:\nordwind\NORTHWND.MDF;Integrated Security=True; User Instance=True; asynchronous processing=true;");
SqlCommand cmd;
StringBuilder consulta = new StringBuilder();

Ahora abrimos la conexión con la base de datos y en un objeto StringBuilder añado todas las inserciones que tengo que hacer.

try
{
  conexion.Open();
  for(int i=0;i<palabras.Length;i++)
  {
      consulta.Append("INSERT into palabras (palabra) VALUES ('" + palabrasIdea.ToString()+"');");
}

Cuando termina de crear todas las inserciones creo una instancia del SqlCommand al que le paso las inserciones y el objeto SqlConnection.

cmd = new SqlCommand(consulta.ToString(), conexion);

Para ejecutar el comando en otro hilo diferente al del programa principal preparo un delegado que se activara cuando termine la operación.

AsyncCallback callback = new AsyncCallback(MetodoCallBack);

Luego ejecuto el comando de forma asíncrona:

cmd.BeginExecuteNonQuery(callback, cmd);

Por último en la función que ejecuta el delegado recogemos el resultado de la operación y ejecutamos EndExecuteNonQuery.

SqlCommand cmd = (SqlCommand)result.AsyncState;
cmd.EndExecuteNonQuery(result);

El código completo sería el siguiente:

private void btnGuardar_Click(object sender, EventArgs e)
        {
            String[] palabras = txtTexto.Text.Split(" ".ToCharArray());
            SqlConnection conexion = new SqlConnection(@"Data Source=.\SQLEXPRESS;AttachDbFilename=C:\ORTHWND.MDF;Integrated Security=True; User Instance=True; asynchronous processing=true;");
            SqlCommand cmd;
            StringBuilder consulta = new StringBuilder();
            try
            {
                conexion.Open();
                for(int i=0;i<palabras.Length;i++)
                {
                        consulta.Append("INSERT into palabras (palabra) VALUES ('" + palabrasIdea.ToString()+"');");
                }
                cmd = new SqlCommand(consulta.ToString(), conexion);
                AsyncCallback callback = new AsyncCallback(MetodoCallBack);
                txtTexto.Enabled = false;
                cmd.BeginExecuteNonQuery(callback, cmd);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
      
        }
        private void MetodoCallBack(IAsyncResult result)
        {
            SqlCommand cmd = (SqlCommand)result.AsyncState;
            cmd.EndExecuteNonQuery(result);
            txtTexto.Enabled = true;
            cmd.Dispose();
        }

Espero que os sirva.

Un saludo