异步编程学习总结1

示例:

static static void Main(string[] args)
        {
            //同步方法
            {
                string filename = @"C:\TEMP\1.txt";
                File.WriteAllText(filename, "hello world");
                string strContext = File.ReadAllText(filename);
                Console.WriteLine(strContext);
            }

        }
static async Task Main(string[] args)
        {

            //异步方法
            {
                string filename = @"C:\TEMP\1.txt";
                await File.WriteAllTextAsync(filename, "hello world");
                string strContext = await File.ReadAllTextAsync(filename);
                Console.WriteLine(strContext);
            }
        }

上面两段代码执行结果是一样的,都是往txt文本中写入一段文字并读取出来。

async,await基本使用总结:
1.异步方法的返回值一般是Task<T>,T是真正的返回值类型,Task<int>。异步方法名字以Async结尾。
2.即使没有返回值,也最好把返回值声明为非泛型的Task。
3.调用异步方法时,一般在方法前面加上await,这样拿到的返回值就是泛型指定的T类型。
4.异步方法的“传染性”,一个方法中如果有await调用,则这个方法也必须修饰为async。
5.如果一个方法既有同步方法,又有异步方法,尽量调用异步方法。
6.async,await不等于“多线程” 。 

调用await之前和之后可能不是一个线程在执行程序,下面做一个测试,在await语句执行前后分别打印出线程的ID。

        /// <summary>
        /// 线程ID测试
        /// </summary>
        /// <returns></returns>
        public static async Task ThreadTest()
        {
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < 10000; i++)
            {
                sb.Append("XXXXXXXXXXXXXXXXXXXXX");
            }
            await File.WriteAllTextAsync(@"C:\TEMP\2.txt", sb.ToString());
            Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
        }

方法调用: 

 static async Task Main(string[] args)
        {
           await ThreadTest();
        }

执行结果:

await调用的等待期间,.net会把当前的线程返回给线程池,等异步方法调用执行完毕后,框架会从线程池再取出来一个线程执行后面的代码。

如果在await语句执行时间很短,可能前后还是同一个线程ID。

异步方法的代码并不会自动在新线程中执行,除非把代码放到新线程中执行。

        /// <summary>
        /// 自定义的异步方法
        /// </summary>
        /// <param name="n"></param>
        /// <returns></returns>
        public static async Task<double> CalcAsync(int n)
        {
            Console.WriteLine("方法中的线程ID:" + Thread.CurrentThread.ManagedThreadId);
            double result = 0;
            Random rand = new Random();
            for (int i = 0; i < n * n; i++)
            {
                result += rand.NextDouble();
            }
            return result;
        }

调用:

static async Task Main(string[] args)
        {
            Console.WriteLine("调用之前的线程ID:" + Thread.CurrentThread.ManagedThreadId);
            double rel = await CalcAsync(5000);
            Console.WriteLine($"rel={rel}");
            Console.WriteLine("调用之后的线程ID:" + Thread.CurrentThread.ManagedThreadId);
        }

执行结果:

自定义一个异步方法名称为CalcAsync,然后在main方法中调用该异步方法,在异步方法调用前后都打印出线程ID,最后发现为同一线程在处理程序。这样说明了不是调用异步方法就会使用新的线程。

如果要想使方法在新的线程中执行,需要把要执行的代码以委托的形式传递给Task.Run(),这样就会从线程池中取出一个线程执行我们的委托,格式如下:

await Task.Run(()=>{

    //耗时操作代码,可以return返回值

})

        /// <summary>
        /// 自定义的异步方法
        /// </summary>
        /// <param name="n"></param>
        /// <returns></returns>
        public static async Task<double> CalcAsync(int n)
        {
            return await Task.Run(() =>
             {
                 Console.WriteLine("方法中的线程ID:" + Thread.CurrentThread.ManagedThreadId);
                 double result = 0;
                 Random rand = new Random();
                 for (int i = 0; i < n * n; i++)
                 {
                     result += rand.NextDouble();
                 }
                 return result;
             });
        }

调用:

static async Task Main(string[] args)
        {
            Console.WriteLine("调用之前的线程ID:" + Thread.CurrentThread.ManagedThreadId);
            double rel = await CalcAsync(5000);
            Console.WriteLine($"rel={rel}");
            Console.WriteLine("调用之后的线程ID:" + Thread.CurrentThread.ManagedThreadId);
        }

执行结果:

 调用异步方法前的线程ID为1,执行异步操作的线程ID为4。执行异步操作时使用的是新的线程。

猜你喜欢

转载自blog.csdn.net/liangmengbk/article/details/121189071