Инкапсулируйте весь блок кода в асинхронную функцию, используя преимущества асинхронного API, и ожидайте любых вызовов асинхронных функций в пределах.
Например,
public async Task ExecuteMyNonQueryAsync() {
using (var conn = GetNewConnection()) {
var query = "DELETE FROM blah blah blah WHERE blah blah;"
await conn.OpenAsync();
using (var cmd = new NpgsqlCommand(query, conn)) {
cmd.Parameters.AddRange(new[] {
new NpgsqlParameter("@a", A),
new NpgsqlParameter("@b", B)
});
await cmd.ExecuteNonQueryAsync();
}
}
}
Можно запустить всю функциюв отдельном потоке с использованием Task.Run
Task.Run(() => ExecuteMyNonQueryAsync());
или в обработчике асинхронных событий
public async void onSomeEvent(object sender, EventArgs args) {
await ExecuteMyNonQueryAsync();
}
Ссылка Асинхронное / ожидание - Лучшие практики асинхронного программирования