官方和老人言,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<StudentController> _logger;
public StudentController(ILogger<StudentController> 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<Student> AddEntityAsync([FromBody] Student student)
{
_logger.LogInformation("异步添加");
return await SavaEntityAsync(student);
}
async Task<Student> 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 异常
/// <summary>
/// 异步调异步API
/// </summary>
/// <returns></returns>
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<Student>(content);
}
else
{
var content = response.Content.ReadAsStringAsync().Result;
Console.WriteLine("同步调同步添加错误返回值:" + content);
}
}
catch (Exception exc)
{
Console.WriteLine(exc.Message);
}
}
}
/// <summary>
/// TaskFactory异步调异步API
/// </summary>
/// <returns></returns>
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<Student>(content);
}
else
{
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine("异步调异步添加错误返回值:" + content);
}
}
catch (Exception exc)
{
Console.WriteLine(exc.Message);
}
});
}
}
/// <summary>
/// 异步调同步API
/// </summary>
/// <returns></returns>
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<Student>(content);
}
else
{
var content = response.Content.ReadAsStringAsync().Result;
Console.WriteLine("同步调同步添加错误返回值:" + content);
}
}
catch (Exception exc)
{
Console.WriteLine(exc.Message);
}
}
}
/// <summary>
/// TaskFactory异步调同步API
/// </summary>
/// <returns></returns>
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<Student>(content);
}
else
{
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine("异步调异步添加错误返回值:" + content);
}
}
catch (Exception exc)
{
Console.WriteLine(exc.Message);
}
});
}
}
#endregion
#region 同步
/// <summary>
/// 同步调同步API
/// </summary>
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<Student>(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<Student>(content);
}
else
{
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine("异步调异步添加错误返回值:" + content);
}
}
catch (Exception exc)
{
Console.WriteLine(exc.Message);
}
}).Result;
}
}
/// <summary>
/// 同步调异步API
/// </summary>
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<Student>(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<Student>(content);
}
else
{
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine("异步调异步添加错误返回值:" + content);
}
}
catch (Exception exc)
{
Console.WriteLine(exc.Message);
}
}).Result;
}
}
#endregion
static async Task<bool> 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<bool>(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 |
客户端调用,异步优势明显;在所有的调用中,服务端的同步要优于异步。
想要更快更方便的了解相关知识,可以关注微信公众号