(十)异步-什么是异步(1)

news2024/11/15 4:55:48

一、什么是异步

启动程序时,系统会在内存中创建一个新的进程。

进程: 构成运行程序的资源的集合。这些资源包括虚地址空间、文件句柄和程序运行所需的其他许多东西。

在进程内部,系统创建了一个称为线程的内核对象,它代表了真正执行的程序。(线程是“执行线程”的简称。)一旦进程建立,系统会在 Main 方法的第一行语句处开始线程的执行。

关于线程:

  • 默认情况下,一个进程只包含一个线程(主线程),从程序的开始一直执行到结束。
  • 线程可以派生其他线程(子线程),因此在任意时刻,一个进程都可能包含不同状态的多个线程,它们执行程序的不同部分。
  • 如果一个进程拥有多个线程,它们将共享进程的资源。
  • 系统为处理器执行所调度的单元是线程,不是进程。

不使用异步的示例:
在我的电脑上,书上的示例中 CountCharacters(1, “htttp://microsoft.com” ); 里调用 DownloadString 方法会卡很久,可能传入的这个微软官方网的服务器有问题。(经我经验所知,微软官方网在某些时候就调用加载这一步时常会变得很慢,尤其登录微软账号的时候,显得更明显)于是我就直接换了个百度首页的地址来测试。

 class MyDownloadString
    {
        Stopwatch sw = new Stopwatch();
        const int LargeNumber = 6000000;

        public void DoRun()
        {
            sw.Start();
            int t1 = CountCharacters(1, "https://www.baidu.com/");
            int t2 = CountCharacters(2, "http://www.illustratedcsharp.com");
            CountToALargeNumber(1);
            CountToALargeNumber(2);
            CountToALargeNumber(3);
            CountToALargeNumber(4);
            Console.WriteLine($"Chars in https://www.baidu.com/   :{t1}");
            Console.WriteLine($"Chars in http://www.illustractedcsharp.com   :{t2}");
        }

        //获取网页源代码内容的长度
        private int CountCharacters(int id,string uriString)
        {
            WebClient wc1 = new WebClient();
            //执行此处记录下时间值
            Console.WriteLine("Starting call {0}   :  {1, 4:N0} ms",
                id, sw.Elapsed.TotalMilliseconds);
            //需要时间下载并获取网页源代码
            string result = wc1.DownloadString(new Uri(uriString));
            Console.WriteLine("  Call {0} completed:    {1, 4:N0}ms",
                id, sw.Elapsed.TotalMilliseconds);

            return result.Length;
        }

        //每间隔一次时间,打印结果。
        //该方法在书上是有两个形参的,
        //但是我觉得有些多余(可能作者为了使代码规范化吧)
        //我为了简便就只使用一个形参
        private void CountToALargeNumber(int id)
        {
            //循环作用:为了让程序执行一段时间,才打印一次结果,以方便查看计数值
            //如果不执行循环,以下打印结果很可能都是相同值。
            for (long i = 0; i < LargeNumber; i++)
                ;

            Console.WriteLine("  End counting {0}  :   {1,  4:N0}ms",
                id, sw.Elapsed.TotalMilliseconds);
        }
    }
  
    class Program
    {
        static void Main(string[] args)
        {
            MyDownloadString ds = new MyDownloadString();
            ds.DoRun();

            Console.ReadKey();
        }
    }

输出结果:

Starting call 1 : 1 ms
Call 1 completed: 694ms
Starting call 2 : 694 ms
Call 2 completed: 3,147ms
End counting 1 : 3,188ms
End counting 2 : 3,235ms
End counting 3 : 3,280ms
End counting 4 : 3,323ms
Chars in https://www.baidu.com/ :9269
Chars in http://www.illustractedcsharp.com :5164

由输出结果可知,执行 DoRun 方法时,该方法里的代码都是按照顺序来执行的。也就是说,每调用一行代码之前,都得要等待上一行代码执行完毕之后才能执行。这里的示例中,由于 调用 DownloadString 方法是需要请求网络时间的, 所以需要等待 DownloadString 方法执行完毕之后,才能执行下一行代码。

请添加图片描述

使用异步的示例

根据上面的示例,把CountCharacters 方法重写为异步调用的方法:
把 DownloadString 改为 DownloadStringTaskAsync,即改为异步调用方法。

      class MyDownloadString
    {
        Stopwatch sw = new Stopwatch();
        const int LargeNumber = 6000000;

        public void DoRun()
        {
            sw.Start();
            //此处代码修改
            Task<int> t1 =  CountCharacters(1, "https://www.baidu.com/");
            Task<int> t2 = CountCharacters(2, "http://www.illustratedcsharp.com");
            CountToALargeNumber(1);
            CountToALargeNumber(2);
            CountToALargeNumber(3);
            CountToALargeNumber(4);
            Console.WriteLine($"Chars in https://www.baidu.com/   :{t1.Result}");//此处代码修改
            Console.WriteLine($"Chars in http://www.illustractedcsharp.com   :{t2.Result}");//此处代码修改
        }

        //获取网页源代码内容的长度,此处代码修改
        private async Task<int> CountCharacters(int id, string uriString)
        {
            WebClient wc1 = new WebClient();
            //执行此处记录下时间值
            Console.WriteLine("Starting call {0}   :  {1, 4:N0} ms",
                id, sw.Elapsed.TotalMilliseconds);
            //需要时间下载并获取网页源代码

            var result = await wc1.DownloadStringTaskAsync(new Uri(uriString));//此处代码修改

            wc1.DownloadString(new Uri(uriString));

            Console.WriteLine("  Call {0} completed:    {1, 4:N0}ms",
                id, sw.Elapsed.TotalMilliseconds);

            return result.Length;
        }

        //每间隔一次时间,打印结果
        private void CountToALargeNumber(int id)
        {
            //循环作用:为了让程序执行一段四件,才打印一次结果,以方便查看计数值
            //如果不执行循环,以下打印结果很可能都是相同值。
            for (long i = 0; i < LargeNumber; i++)
                ;

            Console.WriteLine("  End counting {0}  :   {1,  4:N0}ms",
                id, sw.Elapsed.TotalMilliseconds);
        }
    }
  
    class Program
    {
        static void Main(string[] args)
        {
            MyDownloadString ds = new MyDownloadString();
            ds.DoRun();

            Console.ReadKey();
        }
    }

输出结果:

Starting call 1 : 6 ms
Starting call 2 : 237 ms
End counting 1 : 287ms
End counting 2 : 342ms
Call 1 completed: 384ms
End counting 3 : 394ms
End counting 4 : 440ms
Chars in https://www.baidu.com/ :9269
Call 2 completed: 925ms
Chars in http://www.illustractedcsharp.com :5164

由输出结果可知,程序执行到 DownloadStringTaskAsync 方法时,程序则以异步调用的方式进行。这样可以执行 DownloadStringTaskAsync 的同时,又可以执行下一行代码。

但是,最后两行代码,输出的参数从 t1 改为 t1.Result (从 t2 改为 t2.Result),由于Result 为 Task<int> 类型的,所以这两行代码需要等待 DownloadStringTaskAsync执行完毕后,返回其值才能被输出。如果该方法没有执行完毕,则阻塞并等待期值到来。

以上例子使用了异步调用,但是没有开辟新线程。是因为程序主线程异步调用了 DownloadStringTaskAsync 告诉系统它想要获取资源后,然后继续做自己的事情了。如果中间过程中,在后台系统请求网络得出结果后,会告诉主线程并把结果返回给它,它就停止手上的工作继续处理这个事情,处理完后再继续执行之前手上的工作。

请添加图片描述

由以上两个示例的输出结果可知,如果方法里有需要等待的代码块,那么该方法为同步方法时就会比作为异步方法时,需要耗费的时间就比较长。
(不使用异步示例中,该方法执行的整个过程所耗费的时间为3,323ms;而使用异步后,需要时间为925ms。主要差距的原因就在于,同步方法等待资源时,就会停止手上的工作,直到有结果返回时,才能继续工作。而异步方法等待资源的同时,还继续处理其他事情。)

二、async/await 特性的结构

同步方法: 如果某一个程序调用某个方法,并在等待方法执行所有处理后才继续执行。
异步方法: 在完成其所有方法之前就返回到调用方法。
特性:

  • 调用方法: 该方法调用异步方法,然后在异步方法执行其任务的时候继续执行(可能在相同的线程上,也可能在不同的线程上)。
  • 异步方法: 该方法异步执行其工作,然后立即返回到调用方法。
  • awaite 表达式: 用于异步方法内部,指明需要异步执行的任务。一个异步方法可以包含任意多个 await 表达式,不过如果一个都不包含的话编译器会发出警告。(大概警告:如果不使用 awaite 表达式,则会视为同步执行。)

三、async/await 特性的整体结构

//调用方法
static void Main()
{
Task<int> value DoAsyncStuff.CalculateSumAsync(5,6);
}

//异步方法
staic class DoAsyncStuff
{
public static async Task<int> CalculateSumAsync(int i1,int i2)
{
int sum = await TaskEx.Run(() => GetSum(i1,i2));
return sum;
}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/658210.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

chatgpt赋能python:Python迭代循环详解:从基础到高级

Python迭代循环详解&#xff1a;从基础到高级 在Python中&#xff0c;迭代循环是一种非常重要的编程概念。它能够让我们在程序运行过程中多次访问一个数据集或序列&#xff0c;并且以各种方式对其进行操作。在本文中&#xff0c;我们将深入探讨Python中的迭代循环&#xff0c;…

RFID课程要点总结_1 Introduction

1. Introduction Comparison of different automatic identification technologies 首先明确一下比较对象。human identification&#xff08;cost too high&#xff09;是人力识别就不用说了。 fingerprint identification: stability 稳定&#xff0c;精确度高&#xff1…

GAN:生成对抗网络的突破与应用

第一章&#xff1a;引言 在当今信息时代&#xff0c;人工智能技术的发展如日中天。其中&#xff0c;生成对抗网络&#xff08;GAN&#xff09;作为一种强大的生成模型&#xff0c;引起了广泛的关注和研究。GAN通过两个相互对抗的神经网络&#xff0c;即生成器和判别器&#xf…

【深入浅出Nacos原理及调优】「实战开发专题」采用Docker容器进行部署和搭建Nacos服务以及“坑点”

采用Docker容器进行部署和搭建Nacos服务以及“坑点” Docker容器部署Nacos服务安装Docker下载Nacos镜像docker-compose up部署Derby 单机版部署MySQL 单机版部署修改standalone-mysql.yaml MySQL 集群模式部署 初始化nacos数据库Nacos服务的MySQL版本数据库脚本脚本内容 手动创…

chatgpt赋能python:Python遍历4层的最佳实践

Python遍历4层的最佳实践 如果您对搜索引擎优化&#xff08;SEO&#xff09;和网络爬虫有所了解&#xff0c;那么您可能会知道遍历多层链接的重要性。在这篇文章中&#xff0c;我将介绍如何使用Python编写一个简单而有效的爬虫程序&#xff0c;以遍历4层链接。我会使用标准的P…

AU 简单混音模板,用于AI换声,简单记录

玩AI换声&#xff0c;记录一下快速入门学到的混音经验 混音成品&#xff1a;【AI绫华/RVC2.0】星之所在 https://www.bilibili.com/video/BV1Ao4y1K7P9 人声轨效果器 多频段压缩器 主要用来控制高频的刺刺声 回声 主要用来使声音更加饱满 自适应降噪 减少毛毛躁躁的噪音&…

chatgpt赋能python:如何在Python中选取列表的某一个元素

如何在Python中选取列表的某一个元素 在Python编程中&#xff0c;经常需要从一个包含多个元素的列表中选取特定的元素&#xff0c;以进行下一步的操作或处理。本文将介绍如何通过索引和切片的方式来选取Python列表中的元素。 什么是Python列表 在Python中&#xff0c;列表&a…

chatgpt赋能python:Python怎么遍历ASCII表?

Python怎么遍历ASCII表&#xff1f; 什么是ASCII表&#xff1f; ASCII表&#xff0c;即美国信息交换标准代码&#xff0c;是最早广泛用于计算机中字符编码的标准之一。它包含128个字符&#xff0c;其中包括大写字母、小写字母、数字、标点符号以及其他特殊字符&#xff0c;如…

机器视觉初步5:图像预处理相关技术与原理简介

在机器视觉领域中&#xff0c;图像预处理是一项非常重要的技术。它是指在对图像进行进一步处理之前&#xff0c;对原始图像进行一系列的操作&#xff0c;以提高图像质量、减少噪声、增强图像特征等目的。本文将介绍一些常用的图像预处理技术&#xff0c;并通过配图说明&#xf…

PHP 课后习题解析与笔记——流程控制语句习题

文章目录 &#x1f4cb;前言&#x1f3af;题目一&#x1f3af;题目二&#x1f3af;知识点回顾&#x1f9e9;if...else&#x1f9e9;switch&#x1f9e9;while&#x1f9e9;do...while&#x1f9e9;for&#x1f9e9;foreach &#x1f4dd;最后 &#x1f4cb;前言 这篇文章记录一…

chatgpt赋能python:Python如何遍历文件中的数据

Python如何遍历文件中的数据 Python是一种优秀的编程语言&#xff0c;它在数据处理和文件操作方面非常强大。在本篇文章中&#xff0c;我们将讨论如何使用Python遍历文件中的数据。 什么是遍历文件? 在Python中&#xff0c;遍历文件意味着访问文件中的每一行&#xff0c;并…

油气成因现代模式

根据有机质的性质变化和油气生成沉积有机质的成烃演化可划分为三个阶段&#xff1a;成岩作用阶段、深成作用阶段和准变质作用阶段&#xff1b;相应地又按有机质的成熟程度将有机质成烃演化划分为未成熟阶段、成熟阶段和过成熟阶段&#xff0c;镜质体反射率Ro与有机质的成烃作用…

chatgpt赋能python:Python数据分析入门指南

Python数据分析入门指南 Python已成为数据科学和分析中使用最广泛的编程语言之一。在本指南中&#xff0c;我们将介绍如何使用Python进行数据分析并让您快速上手。 数据分析的基础知识 在开始学习Python进行数据分析之前&#xff0c;您需要了解一些基本的数据分析概念&#…

chatgpt赋能python:Python怎么选取不连续的列

Python怎么选取不连续的列 Python是一种流行的编程语言&#xff0c;可供人们进行多种不同的操作&#xff0c;如编写各种应用程序、数据分析、机器学习和Web开发等。对于Python编程人员来说&#xff0c;选取不连续的列是一项常见任务。在本文中&#xff0c;我们将探讨如何使用P…

chatgpt赋能python:Python怎么退出程序:让你轻松掌握退出Python程序的方法

Python怎么退出程序&#xff1a;让你轻松掌握退出Python程序的方法 Python是一种功能强大、易于学习且具有广泛应用的编程语言。在Python开发中&#xff0c;经常需要退出程序&#xff0c;以便在不需要时释放内存和其他资源。那么&#xff0c;Python怎么退出程序&#xff1f;本…

H.264帧结构和RTSP协议源码框架

目录 1、H264编码原理和基本概念 1.1、h.264编码原理 1.2、h.264编码相关的一些概念 2、H264的NAL单元详解 2.1、VCL和NAL的关系 2.2、H.264视频流分析工具 2.3、h264视频流总体分析 2.4、相关概念 3、H264的NAL单元---sps和pps 3.1、sps和pps详解 3.2、H264的profil…

HELLO算法笔记之散列表(哈希)

一、哈希表 建立键 key 与值 value 之间的映射&#xff0c;实现高效的元素查询。输入一个key&#xff0c;以O&#xff08;1&#xff09;获取对应的value 遍历&#xff1a; # 遍历哈希表 # 遍历键值对 key->value for key, value in mapp.items():print(key, "->&q…

REDIS缓存穿透 击穿 雪崩

一、前言 在我们日常的开发中&#xff0c;无不都是使用数据库来进行数据的存储&#xff0c;由于一般的系统任务中通常不会存在高并发的情况&#xff0c;所以这样看起来并没有什么问题&#xff0c;可是一旦涉及大数据量的需求&#xff0c;比如一些商品抢购的情景&#xff0c;或者…

chatgpt赋能python:Python小数运算:解决精度问题的最佳实践

Python小数运算&#xff1a;解决精度问题的最佳实践 在进行小数运算时&#xff0c;Python是一种十分常用的语言&#xff0c;但在进行小数运算时&#xff0c;由于二进制和十进制之间的转换不完全&#xff0c;可能会导致一些精度问题。为了避免这些问题&#xff0c;让我们一起了…

推荐工具D1

Windows右键菜单管理程序&#xff1a; 主要功能 启用或禁用文件、文件夹、新建、发送到、打开方式、自定义文件格式、IE浏览器、WinX等右键菜单项目 对上述场景右键菜单项目进行修改名称、修改图标、导航注册表位置、导航文件位置、永久删除等操作 对上述场景右键菜单自定义添…