老人言:尽量用异步

  官方和老人言,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

客户端调用,异步优势明显;在所有的调用中,服务端的同步要优于异步。

 

想要更快更方便的了解相关知识,可以关注微信公众号    老人言:尽量用异步

 

 

上一篇:阿里云服务器部署 Hexo 博客


下一篇:老人言:尽量用异步