本文共 20314 字,大约阅读时间需要 67 分钟。
官方和老人言,asp.net core中尽量用异步,为什么呢?接下来是个小demo,看看同步异步的差别吧,或许通过这个demo,就明白官方和老人的良苦用心了。
1、创建一个sql server的表
CREATE TABLE [dbo].[Students]( [StuNo] [varchar](50) NOT NULL, [Name] [varchar](50) NULL, [CardID] [varchar](18) NULL, [Sex] [varchar](4) NULL, [Birthday] [datetime] NULL, [ClassID] [int] NULL, CONSTRAINT [PK_dbo.Students] PRIMARY KEY CLUSTERED ( [StuNo] ASC)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]GO
2、创建一个asp.net core api项目,5.0的
using Microsoft.AspNetCore.Mvc;using Microsoft.Data.SqlClient;using Microsoft.Extensions.Logging;using System;using System.Threading.Tasks;namespace AsyncWebAPI.Controllers{ [ApiController] [Route("[controller]")] public class StudentController : ControllerBase { private readonly ILogger_logger; public StudentController(ILogger logger) { _logger = logger; } [HttpDelete("/deleteall")] public bool DeleteAll() { _logger.LogInformation("删除全部"); using var con = new SqlConnection("server=.;database=TestManageDB;uid=sa;pwd=sa;"); var sql = @"delete from [dbo].[Students]"; var cmd = new SqlCommand(sql, con); con.Open(); var result = cmd.ExecuteNonQuery(); con.Close(); return true; } [HttpPost("/addstudent")] public Student AddEntity([FromBody] Student student) { _logger.LogInformation("同步添加"); return SavaEntity(student); } Student SavaEntity(Student student) { student.StuNo = Guid.NewGuid().ToString(); using var con = new SqlConnection("server=.;database=TestManageDB;uid=sa;pwd=sa;"); var sql = @"INSERT INTO [dbo].[Students] ([StuNo] ,[Name] ,[CardID] ,[Sex] ,[Birthday] ,[ClassID] ) VALUES (@StuNo ,@Name ,@CardID ,@Sex ,@Birthday ,@ClassID )"; var cmd = new SqlCommand(sql, con); cmd.Parameters.Add(new SqlParameter { ParameterName = "@StuNo", Value = student.StuNo, SqlDbType = System.Data.SqlDbType.VarChar }); cmd.Parameters.Add(new SqlParameter { ParameterName = "@Name", Value = student.Name, SqlDbType = System.Data.SqlDbType.VarChar }); cmd.Parameters.Add(new SqlParameter { ParameterName = "@CardID", Value = student.CardID, SqlDbType = System.Data.SqlDbType.VarChar }); cmd.Parameters.Add(new SqlParameter { ParameterName = "@Sex", Value = student.Sex, SqlDbType = System.Data.SqlDbType.VarChar }); cmd.Parameters.Add(new SqlParameter { ParameterName = "@Birthday", Value = student.Birthday, SqlDbType = System.Data.SqlDbType.DateTime }); cmd.Parameters.Add(new SqlParameter { ParameterName = "@ClassID", Value = student.ClassID, SqlDbType = System.Data.SqlDbType.Int }); con.Open(); var result = cmd.ExecuteNonQuery(); con.Close(); return student; } [HttpPost("/addstudentasync")] public async Task AddEntityAsync([FromBody] Student student) { _logger.LogInformation("异步添加"); return await SavaEntityAsync(student); } async Task SavaEntityAsync(Student student) { student.StuNo = Guid.NewGuid().ToString(); using var con = new SqlConnection("server=.;database=TestManageDB;uid=sa;pwd=sa;"); var sql = @"INSERT INTO [dbo].[Students] ([StuNo] ,[Name] ,[CardID] ,[Sex] ,[Birthday] ,[ClassID] ) VALUES (@StuNo ,@Name ,@CardID ,@Sex ,@Birthday ,@ClassID )"; var cmd = new SqlCommand(sql, con); cmd.Parameters.Add(new SqlParameter { ParameterName = "@StuNo", Value = student.StuNo, SqlDbType = System.Data.SqlDbType.VarChar }); cmd.Parameters.Add(new SqlParameter { ParameterName = "@Name", Value = student.Name, SqlDbType = System.Data.SqlDbType.VarChar }); cmd.Parameters.Add(new SqlParameter { ParameterName = "@CardID", Value = student.CardID, SqlDbType = System.Data.SqlDbType.VarChar }); cmd.Parameters.Add(new SqlParameter { ParameterName = "@Sex", Value = student.Sex, SqlDbType = System.Data.SqlDbType.VarChar }); cmd.Parameters.Add(new SqlParameter { ParameterName = "@Birthday", Value = student.Birthday, SqlDbType = System.Data.SqlDbType.DateTime }); cmd.Parameters.Add(new SqlParameter { ParameterName = "@ClassID", Value = student.ClassID, SqlDbType = System.Data.SqlDbType.Int }); await con.OpenAsync(); var result = await cmd.ExecuteNonQueryAsync(); await con.CloseAsync(); return student; } } public class Student { public string StuNo { get; set; } public string Name { get; set; } public string CardID { get; set; } public string Sex { get; set; } public DateTime Birthday { get; set; } public int ClassID { get; set; } }}
3、创建一个控制台程序,了是.net core 5.0的
using Newtonsoft.Json;using System;using System.Net.Http;using System.Text;using System.Threading.Tasks;namespace AsyncRquestClient{ class ProgramAsync { static int times = 100; static async Task Main(string[] args) { while (true) { Console.WriteLine("输入循环次数"); times = int.Parse(Console.ReadLine()); #region 同步 Console.WriteLine("-----------------同步调同步API------------------"); SyncCallSyncAPI(); Console.ReadLine(); Console.WriteLine("-----------------同步调异步API------------------"); SyncCallAsyncAPI(); Console.ReadLine(); Console.WriteLine("-----------------TaskFactory同步调同步API------------------"); TaskFactorySyncCallSyncAPI(); Console.ReadLine(); Console.WriteLine("-----------------TaskFactory同步调异步API------------------"); TaskFactorySyncCallAsyncAPI(); Console.ReadLine(); #endregion #region 异步 Console.WriteLine("-----------------异步调异步API------------------"); await AsyncCallAsyncAPI(); Console.ReadLine(); Console.WriteLine("-----------------异步调同步API------------------"); await AsyncCallSyncAPI(); Console.ReadLine(); Console.WriteLine("-----------------TaskFactory异步调异步API------------------"); await TaskFactoryAsyncCallAsyncAPI(); Console.ReadLine(); Console.WriteLine("-----------------TaskFactory异步调同步API------------------"); await TaskFactoryAsyncCallSyncAPI(); Console.ReadLine(); #endregion } } #region 异常 ////// 异步调异步API /// ///async static Task AsyncCallAsyncAPI() { var r = DeleteAllAsync().Result; Console.WriteLine($"异步调异步API开始时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff")}"); for (int i = 1; i <= times; i++) { try { var student = new Student { Name = "张三" + i, Birthday = DateTime.Now, CardID = "C0000" + i, ClassID = 1, Sex = "男" }; using var client = new HttpClient(); client.BaseAddress = new Uri("https://localhost:5001"); var request = new HttpRequestMessage(HttpMethod.Post, "addstudentasync"); request.Content = new StringContent(JsonConvert.SerializeObject(student), Encoding.UTF8, "application/json"); var response = await client.SendAsync(request); if (response.IsSuccessStatusCode) { var content = await response.Content.ReadAsStringAsync(); var stu = JsonConvert.DeserializeObject (content); } else { var content = response.Content.ReadAsStringAsync().Result; Console.WriteLine("同步调同步添加错误返回值:" + content); } } catch (Exception exc) { Console.WriteLine(exc.Message); } } } /// /// TaskFactory异步调异步API /// ///static async Task TaskFactoryAsyncCallAsyncAPI() { var r = await DeleteAllAsync(); Console.WriteLine($"TaskFactory异步调异步开API始时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff")}"); for (int i = 1; i <= times; i++) { await Task.Factory.StartNew(async () => { try { var student = new Student { Name = "张三" + i, Birthday = DateTime.Now, CardID = "C0000" + i, ClassID = 1, Sex = "男" }; using var client = new HttpClient(); client.BaseAddress = new Uri("https://localhost:5001"); var request = new HttpRequestMessage(HttpMethod.Post, "addstudentasync"); request.Content = new StringContent(JsonConvert.SerializeObject(student), Encoding.UTF8, "application/json"); var response = await client.SendAsync(request); if (response.IsSuccessStatusCode) { var content = await response.Content.ReadAsStringAsync(); var stu = JsonConvert.DeserializeObject (content); } else { var content = await response.Content.ReadAsStringAsync(); Console.WriteLine("异步调异步添加错误返回值:" + content); } } catch (Exception exc) { Console.WriteLine(exc.Message); } }); } } /// /// 异步调同步API /// ///async static Task AsyncCallSyncAPI() { var r = DeleteAllAsync().Result; Console.WriteLine($"异步调同步API开始时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff")}"); for (int i = 1; i <= times; i++) { try { var student = new Student { Name = "张三" + i, Birthday = DateTime.Now, CardID = "C0000" + i, ClassID = 1, Sex = "男" }; using var client = new HttpClient(); client.BaseAddress = new Uri("https://localhost:5001"); var request = new HttpRequestMessage(HttpMethod.Post, "addstudent"); request.Content = new StringContent(JsonConvert.SerializeObject(student), Encoding.UTF8, "application/json"); var response = await client.SendAsync(request); if (response.IsSuccessStatusCode) { var content = await response.Content.ReadAsStringAsync(); var stu = JsonConvert.DeserializeObject (content); } else { var content = response.Content.ReadAsStringAsync().Result; Console.WriteLine("同步调同步添加错误返回值:" + content); } } catch (Exception exc) { Console.WriteLine(exc.Message); } } } /// /// TaskFactory异步调同步API /// ///static async Task TaskFactoryAsyncCallSyncAPI() { var r = await DeleteAllAsync(); Console.WriteLine($"TaskFactory异步调同步API开始时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff")}"); for (int i = 1; i <= times; i++) { await Task.Factory.StartNew(async () => { try { var student = new Student { Name = "张三" + i, Birthday = DateTime.Now, CardID = "C0000" + i, ClassID = 1, Sex = "男" }; using var client = new HttpClient(); client.BaseAddress = new Uri("https://localhost:5001"); var request = new HttpRequestMessage(HttpMethod.Post, "addstudent"); request.Content = new StringContent(JsonConvert.SerializeObject(student), Encoding.UTF8, "application/json"); var response = await client.SendAsync(request); if (response.IsSuccessStatusCode) { var content = await response.Content.ReadAsStringAsync(); var stu = JsonConvert.DeserializeObject (content); } else { var content = await response.Content.ReadAsStringAsync(); Console.WriteLine("异步调异步添加错误返回值:" + content); } } catch (Exception exc) { Console.WriteLine(exc.Message); } }); } } #endregion #region 同步 /// /// 同步调同步API /// static void SyncCallSyncAPI() { var r = DeleteAllAsync().Result; Console.WriteLine($"同步调同步开始时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff")}"); for (int i = 1; i <= times; i++) { try { var student = new Student { Name = "张三" + i, Birthday = DateTime.Now, CardID = "C0000" + i, ClassID = 1, Sex = "男" }; using var client = new HttpClient(); client.BaseAddress = new Uri("https://localhost:5001"); var request = new HttpRequestMessage(HttpMethod.Post, "addstudent"); request.Content = new StringContent(JsonConvert.SerializeObject(student), Encoding.UTF8, "application/json"); var response = client.SendAsync(request).Result; if (response.IsSuccessStatusCode) { var content = response.Content.ReadAsStringAsync().Result; var stu = JsonConvert.DeserializeObject(content); } else { var content = response.Content.ReadAsStringAsync().Result; Console.WriteLine("同步调同步添加错误返回值:" + content); } } catch (Exception exc) { Console.WriteLine(exc.Message); } } } static void TaskFactorySyncCallSyncAPI() { var r = DeleteAllAsync().Result; Console.WriteLine($"TaskFactory异步调同步API开始时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff")}"); for (int i = 1; i <= times; i++) { var result = Task.Factory.StartNew(async () => { try { var student = new Student { Name = "张三" + i, Birthday = DateTime.Now, CardID = "C0000" + i, ClassID = 1, Sex = "男" }; using var client = new HttpClient(); client.BaseAddress = new Uri("https://localhost:5001"); var request = new HttpRequestMessage(HttpMethod.Post, "addstudent"); request.Content = new StringContent(JsonConvert.SerializeObject(student), Encoding.UTF8, "application/json"); var response = await client.SendAsync(request); if (response.IsSuccessStatusCode) { var content = await response.Content.ReadAsStringAsync(); var stu = JsonConvert.DeserializeObject (content); } else { var content = await response.Content.ReadAsStringAsync(); Console.WriteLine("异步调异步添加错误返回值:" + content); } } catch (Exception exc) { Console.WriteLine(exc.Message); } }).Result; } } /// /// 同步调异步API /// static void SyncCallAsyncAPI() { var r = DeleteAllAsync().Result; Console.WriteLine($"同步调异步开始时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff")}"); for (int i = 1; i <= times; i++) { try { var student = new Student { Name = "张三" + i, Birthday = DateTime.Now, CardID = "C0000" + i, ClassID = 1, Sex = "男" }; using var client = new HttpClient(); client.BaseAddress = new Uri("https://localhost:5001"); var request = new HttpRequestMessage(HttpMethod.Post, "addstudentasync"); request.Content = new StringContent(JsonConvert.SerializeObject(student), Encoding.UTF8, "application/json"); var response = client.SendAsync(request).Result; if (response.IsSuccessStatusCode) { var content = response.Content.ReadAsStringAsync().Result; var stu = JsonConvert.DeserializeObject(content); } else { var content = response.Content.ReadAsStringAsync().Result; Console.WriteLine("同步调异步添加错误返回值:" + content); } } catch (Exception exc) { Console.WriteLine(exc.Message); } } } static void TaskFactorySyncCallAsyncAPI() { var r = DeleteAllAsync().Result; Console.WriteLine($"TaskFactory异步调同步API开始时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff")}"); for (int i = 1; i <= times; i++) { var result = Task.Factory.StartNew(async () => { try { var student = new Student { Name = "张三" + i, Birthday = DateTime.Now, CardID = "C0000" + i, ClassID = 1, Sex = "男" }; using var client = new HttpClient(); client.BaseAddress = new Uri("https://localhost:5001"); var request = new HttpRequestMessage(HttpMethod.Post, "addstudentasync"); request.Content = new StringContent(JsonConvert.SerializeObject(student), Encoding.UTF8, "application/json"); var response = await client.SendAsync(request); if (response.IsSuccessStatusCode) { var content = await response.Content.ReadAsStringAsync(); var stu = JsonConvert.DeserializeObject (content); } else { var content = await response.Content.ReadAsStringAsync(); Console.WriteLine("异步调异步添加错误返回值:" + content); } } catch (Exception exc) { Console.WriteLine(exc.Message); } }).Result; } } #endregion static async Task DeleteAllAsync() { using var client = new HttpClient(); client.BaseAddress = new Uri("https://localhost:5001"); var request = new HttpRequestMessage(HttpMethod.Delete, "deleteall"); var response = await client.SendAsync(request); if (response.IsSuccessStatusCode) { var content = await response.Content.ReadAsStringAsync(); var result = JsonConvert.DeserializeObject (content); return result; } else { var content = await response.Content.ReadAsStringAsync(); Console.WriteLine("删除错误返回值:" + content); return false; } } } public class Student { public string StuNo { get; set; } public string Name { get; set; } public string CardID { get; set; } public string Sex { get; set; } public DateTime Birthday { get; set; } public int ClassID { get; set; } }}
4、在sql查询分析器中用这里的语句采集结果
--检查记录数是否完整select count(*) from students;--查询时间隔select datediff(millisecond,(select min(birthday) as mi from students),(select max(birthday) as ma from students));
结果如下:
1000次请求 | 同步调同步API | 同步调异步API | TaskFactory同步调同步API | TaskFactory同步调异步API | 异步调异步API | 异步调同步API | TaskFactory异步调异步API | TaskFactory异步调同步API |
1次(毫秒) | 3190 | 3574 | 390 | 374 | 3393 | 3140 | 356 | 387 |
2次(毫秒 | 3194 | 3324 | 386 | 454 | 3370 | 3153 | 477 | 356 |
3次(毫秒 | 3350 | 3343 | 443 | 397 | 3323 | 3196 | 417 | 406 |
4次(毫秒 | 3207 | 3340 | 360 | 423 | 3206 | 3083 | 433 | 403 |
5次(毫秒 | 3214 | 3347 | 426 | 490 | 3167 | 3136 | 430 | 387 |
平均 | 3231 | 3385.6 | 401 | 427.6 | 3291.8 | 3141.6 | 422.6 | 387.8 |
客户端调用,异步优势明显;在所有的调用中,服务端的同步要优于异步。
转载地址:http://qyudi.baihongyu.com/