放弃Task.Run!这才是.NET异步编程的正确打开方式
				
									
					
					
						 | 
						
							
							admin 
							
							
								2025年6月18日 21:36
								本文热度 1450
							
							 
						 | 
					
					
				 
				在.NET中进行异步编程时,许多开发者习惯使用Task.Run将工作卸载到线程池,但这往往不是最佳选择。本文将介绍.NET异步编程的正确方法,帮助你避免常见陷阱并充分发挥异步编程的优势。
关键要点总结
- 大多数.NET库都提供了异步版本的方法(如
File.ReadAllTextAsync、HttpClient.GetStringAsync) - 避免使用
Task.Run包装同步方法,这会增加线程池压力并可能导致性能下降 
- 适用于I/O密集型操作(网络请求、文件读写、数据库查询等)
 - 对于CPU密集型操作,
Task.Run可能仍然是合适的选择,但应谨慎使用 
- 使用
await foreach处理大型数据集,避免内存溢出 - 结合EF Core的
AsAsyncEnumerable实现高效的数据处理 
- 使用
SemaphoreSlim控制并发度,避免资源耗尽 
- 使用
CancellationToken实现操作取消,提高响应性 
- 在UI线程上永远不要阻塞(避免使用
.Result或.Wait()) 
遵循这些最佳实践,你可以编写出更高效、更可靠的异步代码,充分发挥.NET平台的异步编程能力,同时避免常见的陷阱和性能问题。
using System;using System.IO;using System.Net.Http;using System.Text.Json;using System.Threading;using System.Threading.Tasks;
public static class AsyncBestPractices{        public static async Task<string> DownloadFileAsync(string url)    {        using var client = new HttpClient();                return await client.GetStringAsync(url);
                    }
        public static async Task ProcessFileAsync(string filePath)    {                await using var fileStream = new FileStream(            filePath,             FileMode.Open,             FileAccess.Read,             FileShare.Read,            bufferSize: 4096,             useAsync: true); 
        using var reader = new StreamReader(fileStream);        string content = await reader.ReadToEndAsync();
                var processedContent = ProcessContent(content);
                await using var outputStream = new FileStream(            filePath + ".processed",             FileMode.Create,             FileAccess.Write,             FileShare.None,            bufferSize: 4096,             useAsync: true);
        using var writer = new StreamWriter(outputStream);        await writer.WriteAsync(processedContent);    }
    private static string ProcessContent(string content)    {                return content.ToUpper();    }
        public static async Task<Order> GetOrderAsync(int orderId)    {        using var context = new OrderDbContext();                return await context.Orders.FindAsync(orderId);    }
        public static async Task ProcessOrdersAsync()    {        using var context = new OrderDbContext();
                await foreach (var order in context.Orders.AsAsyncEnumerable())        {            await ProcessOrderAsync(order);        }    }
    private static async Task ProcessOrderAsync(Order order)    {                await Task.Delay(10);         Console.WriteLine($"处理订单: {order.Id}");    }
        public static async Task DownloadMultipleFilesAsync(string[] urls)    {                var downloadTasks = urls.Select(url => DownloadAndSaveFileAsync(url));
                await Task.WhenAll(downloadTasks);    }
    private static async Task DownloadAndSaveFileAsync(string url)    {        using var client = new HttpClient();        var content = await client.GetStringAsync(url);
        var fileName = Path.GetFileName(url);        await File.WriteAllTextAsync(fileName, content);    }
        public static async Task SafeDownloadAsync(string url)    {        try        {            using var client = new HttpClient();            var content = await client.GetStringAsync(url);            await ProcessDownloadedContentAsync(content);        }        catch (HttpRequestException ex)        {            Console.WriteLine($"下载失败: {ex.Message}");        }        catch (OperationCanceledException)        {            Console.WriteLine("操作已取消");        }        catch (Exception ex)        {            Console.WriteLine($"发生未知错误: {ex.Message}");        }    }
    private static Task ProcessDownloadedContentAsync(string content)    {                return Task.CompletedTask;    }
        public static async Task CancelableOperationAsync(CancellationToken cancellationToken)    {        using var client = new HttpClient();
        try        {                        var response = await client.GetAsync("https://example.com", cancellationToken);
            if (response.IsSuccessStatusCode)            {                var content = await response.Content.ReadAsStringAsync(cancellationToken);                Console.WriteLine($"下载完成: {content.Length} 字符");            }        }        catch (OperationCanceledException)        {            Console.WriteLine("操作被用户取消");        }    }
            public static async void ButtonClickHandler(object sender, EventArgs e)    {                
                await LongRunningOperationAsync();    }
    private static async Task LongRunningOperationAsync()    {        await Task.Delay(5000);         Console.WriteLine("操作完成");    }
        public static async IAsyncEnumerable<string> ReadLinesAsync(string filePath)    {        await using var fileStream = new FileStream(            filePath,             FileMode.Open,             FileAccess.Read,             FileShare.Read,            bufferSize: 4096,             useAsync: true);
        using var reader = new StreamReader(fileStream);
        string line;        while ((line = await reader.ReadLineAsync()) != null)        {            yield return line;        }    }
        public static async Task ProcessItemsWithThrottleAsync(IEnumerable<string> items, int maxConcurrency = 5)    {        var semaphore = new SemaphoreSlim(maxConcurrency);
        var tasks = items.Select(async item =>        {            await semaphore.WaitAsync();
            try            {                await ProcessItemAsync(item);            }            finally            {                semaphore.Release();            }        });
        await Task.WhenAll(tasks);    }
    private static async Task ProcessItemAsync(string item)    {        await Task.Delay(100);         Console.WriteLine($"处理项: {item}");    }}
public class OrderDbContext : DbContext{    public DbSet<Order> Orders { get; set; }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)    {        optionsBuilder.UseSqlServer("YourConnectionString");    }}
public class Order{    public int Id { get; set; }    public string CustomerName { get; set; }    public DateTime OrderDate { get; set; }}
阅读原文:原文链接
该文章在 2025/6/19 18:20:16 编辑过