老人言:儘量用異步

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

客戶端調用,異步優勢明顯;在所有的調用中,服務端的同步要優於異步。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章