当前位置: 首页 > news >正文

【智能大数据分析 | 实验一】MapReduce实验:单词计数

在这里插入图片描述

【作者主页】Francek Chen
【专栏介绍】 ⌈ ⌈ 智能大数据分析 ⌋ ⌋ 智能大数据分析是指利用先进的技术和算法对大规模数据进行深入分析和挖掘,以提取有价值的信息和洞察。它结合了大数据技术、人工智能(AI)、机器学习(ML)和数据挖掘等多种方法,旨在通过自动化的方式分析复杂数据集,发现潜在的价值和关联性,实现数据的自动化处理和分析,从而支持决策和优化业务流程。与传统的人工分析相比,智能大数据分析具有自动化、深度挖掘、实时性和可视化等特点。智能大数据分析广泛应用于各个领域,包括金融服务、医疗健康、零售、市场营销等,帮助企业做出更为精准的决策,提升竞争力。
【GitCode】专栏资源保存在我的GitCode仓库:https://gitcode.com/Morse_Chen/Intelligent_bigdata_analysis。

文章目录

    • 一、实验目的
    • 二、实验要求
    • 三、实验原理
      • (一)MapReduce 编程
      • (二)Java API 解析
    • 四、实验环境
    • 五、实验步骤
      • (一)启动 Hadoop
      • (二)验证 HDFS 上没有 wordcount 的文件夹
      • (三)上传数据文件到 HDFS
      • (四)编写 MapReduce 程序
      • (五)使用 Eclipse 开发工具将该代码打包
    • 六、实验结果
    • 七、实验心得


一、实验目的

基于 MapReduce 思想,编写 WordCount 程序。

二、实验要求

  1. 理解 MapReduce 编程思想;
  2. 会编写 MapReduce 版本 WordCount;
  3. 会执行该程序;
  4. 自行分析执行过程。

三、实验原理

MapReduce 是一种计算模型,简单的说就是将大批量的工作(数据)分解(MAP)执行,然后再将结果合并成最终结果(REDUCE)。这样做的好处是可以在任务被分解后,可以通过大量机器进行并行计算,减少整个操作的时间。

适用范围:数据量大,但是数据种类小可以放入内存。

基本原理及要点:将数据交给不同的机器去处理,数据划分,结果归约。

理解 MapReduce 和 Yarn:在新版 Hadoop 中,Yarn 作为一个资源管理调度框架,是 Hadoop 下 MapReduce 程序运行的生存环境。其实 MapRuduce 除了可以运行 Yarn 框架下,也可以运行在诸如 Mesos,Corona 之类的调度框架上,使用不同的调度框架,需要针对 Hadoop 做不同的适配。

一个完成的 MapReduce 程序在 Yarn 中执行过程如下:

(1)ResourcManager JobClient 向 ResourcManager 提交一个 job。

(2)ResourcManager 向 Scheduler 请求一个供 MRAppMaster 运行的 container,然后启动它。

(3)MRAppMaster 启动起来后向 ResourcManager 注册。

(4)ResourcManagerJobClient 向 ResourcManager 获取到 MRAppMaster 相关的信息,然后直接与 MRAppMaster 进行通信。

(5)MRAppMaster 算 splits 并为所有的 map 构造资源请求。

(6)MRAppMaster 做一些必要的 MR OutputCommitter 的准备工作。

(7)MRAppMaster 向 RM(Scheduler) 发起资源请求,得到一组供 map/reduce task 运行的 container,然后与 NodeManager 一起对每一个 container 执行一些必要的任务,包括资源本地化等。

(8)MRAppMaster 监视运行着的 task 直到完成,当 task 失败时,申请新的 container 运行失败的 task。

(9)当每个 map/reduce task 完成后,MRAppMaster 运行 MR OutputCommitter 的 cleanup 代码,也就是进行一些收尾工作。

(10)当所有的 map/reduce 完成后,MRAppMaster 运行 OutputCommitter 的必要的 job commit 或者 abort APIs。

(11)MRAppMaster 退出。

(一)MapReduce 编程

编写在 Hadoop 中依赖 Yarn 框架执行的 MapReduce 程序,并不需要自己开发 MRAppMaster 和 YARNRunner,因为 Hadoop 已经默认提供通用的 YARNRunner 和 MRAppMaster 程序, 大部分情况下只需要编写相应的 Map 处理和 Reduce 处理过程的业务程序即可。

编写一个 MapReduce 程序并不复杂,关键点在于掌握分布式的编程思想和方法,主要将计算过程分为以下五个步骤:

(1)迭代。遍历输入数据,并将之解析成 key/value 对。

(2)将输入 key/value 对映射 (map) 成另外一些 key/value 对。

(3)依据 key 对中间数据进行分组 (grouping)。

(4)以组为单位对数据进行归约 (reduce)。

(5)迭代。将最终产生的 key/value 对保存到输出文件中。

(二)Java API 解析

(1)InputFormat:用于描述输入数据的格式,常用的为 TextInputFormat 提供如下两个功能:

数据切分: 按照某个策略将输入数据切分成若干个 split,以便确定 Map Task 个数以及对应的 split。

为 Mapper 提供数据:给定某个 split,能将其解析成一个个 key/value 对。

(2)OutputFormat:用于描述输出数据的格式,它能够将用户提供的 key/value 对写入特定格式的文件中。

(3)Mapper/Reducer:Mapper/Reducer 中封装了应用程序的数据处理逻辑。

(4)Writable:Hadoop 自定义的序列化接口。实现该类的接口可以用作 MapReduce 过程中的 value 数据使用。

(5)WritableComparable:在 Writable 基础上继承了 Comparable 接口,实现该类的接口可以用作 MapReduce 过程中的 key 数据使用。(因为 key 包含了比较排序的操作)。

四、实验环境

虚拟机软件:VMware 16 Pro
Linux 操作系统版本:CentOS-7-64位
Java 版本:jdk1.7.0_79
Hadoop 版本:hadoop-2.7.1

JDK 和 Hadoop 的安装配置可参考:大数据存储技术(1)—— Hadoop简介及安装配置(以上版本 Java 和 Hadoop 的安装包可到文末链接下载)

五、实验步骤

本实验主要分为,确认前期准备,编写 MapReduce 程序,打包提交代码。查看运行结果这几个步骤,详细如下:

(一)启动 Hadoop

执行命令启动前面实验部署好的 Hadoop 系统。

start-all.sh

在这里插入图片描述

(二)验证 HDFS 上没有 wordcount 的文件夹

hadoop fs -ls /

在这里插入图片描述

此时 HDFS 上应该是没有 wordcount 文件夹。

(三)上传数据文件到 HDFS

先在 HDFS 上新建目录datasets,然后将数据文件上传到 HDFS。

hadoop fs -mkdir /datasets
hadoop fs -ls /
hadoop fs -put /usr/local/datasets/word /datasets

在这里插入图片描述

查看数据文件word的内容。

hadoop fs -cat /datasets/word

在这里插入图片描述

(四)编写 MapReduce 程序

首先,我们在 Eclipse 中新建一个 Map/Reduce Project。

在这里插入图片描述
接着,正确导入 Hadoop 的路径。

在这里插入图片描述
然后,开始编写程序。主要编写 Map 和 Reduce 类,其中 Map 过程需要继承org.apache.hadoop.mapreduce包中Mapper类,并重写其map方法;Reduce过程需要继承org.apache.hadoop.mapreduce包中Reduce类,并重写其reduce方法。

在这里插入图片描述
最后,完整代码如下。

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.mapreduce.lib.partition.HashPartitioner;import java.io.IOException;
import java.util.StringTokenizer;public class WordCount {public static class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable> {private final static IntWritable one = new IntWritable(1);private Text word = new Text();//map方法,划分一行文本,读一个单词写出一个<单词,1>public void map(Object key, Text value, Context context)throws IOException, InterruptedException {StringTokenizer itr = new StringTokenizer(value.toString());while (itr.hasMoreTokens()) {word.set(itr.nextToken());context.write(word, one);//写出<单词,1>}}}//定义reduce类,对相同的单词,把它们中的VList值全部相加public static class IntSumReducer extends Reducer<Text, IntWritable, Text, IntWritable> {private IntWritable result = new IntWritable();public void reduce(Text key, Iterable<IntWritable> values,Context context)throws IOException, InterruptedException {int sum = 0;for (IntWritable val : values) {sum += val.get();//相当于<Hello,1><Hello,1>,将两个1相加}result.set(sum);context.write(key, result);//写出这个单词,和这个单词出现次数<单词,单词出现次数>}}public static void main(String[] args) throws Exception {//主方法,函数入口Configuration conf = new Configuration();           //实例化配置文件类Job job = new Job(conf, "WordCount");             //实例化Job类job.setInputFormatClass(TextInputFormat.class);     //指定使用默认输入格式类TextInputFormat.setInputPaths(job, args[0]);      //设置待处理文件的位置job.setJarByClass(WordCount.class);               //设置主类名job.setMapperClass(TokenizerMapper.class);        //指定使用上述自定义Map类job.setCombinerClass(IntSumReducer.class);        //指定开启Combiner函数job.setMapOutputKeyClass(Text.class);            //指定Map类输出的,K类型job.setMapOutputValueClass(IntWritable.class);     //指定Map类输出的,V类型job.setPartitionerClass(HashPartitioner.class);       //指定使用默认的HashPartitioner类job.setReducerClass(IntSumReducer.class);         //指定使用上述自定义Reduce类job.setNumReduceTasks(Integer.parseInt(args[2]));  //指定Reduce个数job.setOutputKeyClass(Text.class);                //指定Reduce类输出的,K类型job.setOutputValueClass(Text.class);               //指定Reduce类输出的,V类型job.setOutputFormatClass(TextOutputFormat.class);  //指定使用默认输出格式类TextOutputFormat.setOutputPath(job, new Path(args[1]));    //设置输出结果文件位置System.exit(job.waitForCompletion(true) ? 0 : 1);    //提交任务并监控任务状态}
}

注意:这里的 jre 要设置成 1.7 版本的,不然后面运行程序会导致版本不兼容的相关错误。

在这里插入图片描述

(五)使用 Eclipse 开发工具将该代码打包

假定打包后的文件名为hdpAction.jar,并使用 WinSCP 上传至 Linux 系统。

在这里插入图片描述
在这里插入图片描述
可使用如下命令向 YARN 集群提交本应用。

yarn jar hdpAction.jar /datasets/word /wordcount 1

其中yarn为命令,jar为命令参数,后面紧跟打包后的代码地址,/datasets/word为输入文件在 HDFS 中的位置,/wordcount为输出文件在 HDFS 中的位置,1通常指的是要使用的reduce任务的数量。

六、实验结果

1. 程序运行成功控制台上的显示内容

在这里插入图片描述

2. 在HDFS上查看结果

hadoop fs -ls /wordcount
hadoop fs -cat /wordcount/part-r-00000

在这里插入图片描述

七、实验心得

  在进行 MapReduce 单词计数实验的过程中,我深刻体会到分布式计算的强大能力和处理大规模数据的复杂性。通过这个实验,我不仅掌握了 MapReduce 的基本流程,还加深了对其背后原理的理解。

  实验的第一步是 Mapper 阶段。在这一阶段,我的任务是将输入的文本数据进行拆分,提取出每一个单词,并为其分配一个计数值。这个过程虽然看似简单,但实际上却涉及到数据的清洗和格式化。在实际操作中,我意识到单词的分隔符、大小写的处理以及标点符号的剔除都对最终结果产生重大影响。因此,我在编写 Mapper 代码时,特别注重了这些细节,确保能准确无误地提取出每一个单词。接下来是 Reducer 阶段,主要任务是对来自多个 Mapper 的输出进行汇总。通过对单词及其计数进行合并,我能够得到每个单词在整个数据集中的总出现次数。这一过程让我体会到聚合操作的重要性,以及如何高效地处理和合并数据。特别是在面对大规模数据时,优化排序和分组算法显得尤为关键。为了提高效率,我还学习了如何利用内存中的数据结构,以便更快地进行查找和更新。

  通过这个实验,我不仅掌握了 MapReduce 的基本语法和使用方法,更重要的是,我理解了其背后的设计思想和应用场景。在大数据时代,MapReduce 作为一种有效的分布式计算模型,能够帮助我们处理海量数据,为数据分析、机器学习等领域提供强有力的支持。最后,这个实验让我认识到,编写高效的 MapReduce 程序需要对数据结构和算法有深刻的理解,尤其是在性能优化方面。未来,我希望能在此基础上深入研究更高级的分布式计算框架,如 Apache Spark 等,进一步提升自己的技术水平。

  总的来说,这次 MapReduce 单词计数实验不仅提升了我的编程能力,还让我对大数据处理有了更深入的认识,增强了我在未来相关领域继续深入研究的动力。我期待将所学应用于实际项目中,探索更多可能性。

:以上文中的数据文件及相关资源下载地址:
链接:https://pan.quark.cn/s/a40065ab5906
提取码:4r8J

相关文章:

【智能大数据分析 | 实验一】MapReduce实验:单词计数

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈智能大数据分析 ⌋ ⌋ ⌋ 智能大数据分析是指利用先进的技术和算法对大规模数据进行深入分析和挖掘&#xff0c;以提取有价值的信息和洞察。它结合了大数据技术、人工智能&#xff08;AI&#xff09;、机器学习&#xff08;ML&a…...

Git 版本控制--git restore和git reset

git restore 和 git reset 是 Git 版本控制系统中两个用于撤销更改的命令&#xff0c;但它们的作用范围和用途有所不同。 git restore git restore 是 Git 版本控制系统中的一个命令&#xff0c;用于撤销工作目录中的更改&#xff0c;但不影响暂存区&#xff08;staging area…...

DBAPI如何实现插入数据前先判断数据是否存在,存在就更新,不存在就插入

DBAPI实现数据不存在即插入、存在即更新 场景 往数据库插入数据的时候&#xff0c;需要先判断一下记录是否在数据库已经存在&#xff0c;如果已经存在就更新记录&#xff0c;如果不存在&#xff0c;才插入数据。 实现方案 采用存储过程实现&#xff0c;以mysql为例子 创建存储过…...

【渗透测试】-灵当CRM系统-sql注入漏洞复现

文章目录 概要   灵当CRM系统sql注入漏洞&#xff1a;   具体实例&#xff1a;  技术名词解释  小结 概要 近期灵当CRM系统爆出sql注入漏洞&#xff0c;我们来进行nday复现。 灵当CRM系统sql注入漏洞&#xff1a; Python sqlmap.py -u "http://0.0.0.0:0000/c…...

c语言练习题1(数组和循环)

1实现一个对整形数组的冒泡排序 冒泡排序&#xff08;Bubble Sort&#xff09;是一种简单的排序算法。它重复地遍历要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果它们的顺序错误就把它们交换过来。遍历数列的工作是重复进行的&#xff0c;直到没有再需要交换的元…...

实验3 Hadoop集群运行环境搭建和使用

实验3 Hadoop集群运行环境搭建和使用 一、实验介绍 本节实验旨在引导学生通过实际操作搭建一个基本的Hadoop集群,并进行基本的使用验证。实验包括在集群节点上添加域名映射以实现节点间的相互识别,配置免密SSH登录以便无密码访问各节点,安装和配置JDK以满足Hadoop的运行需求…...

前端文件上传全过程

特别说明&#xff1a;ui框架使用的是蚂蚁的antd 这里主要是学习前端上传接口的传递参数包括前端上传之前对于代码的整理 一、第一步将前端页面画出来 源代码&#xff1a; /** 费用管理 - IT费用管理 - 费用数据上传 */ import { useState } from "react"; import {…...

MySQL中的函数简单总结,以及TCL语句的简单讲解

文章目录 一、函数1、ifnull2、if3、case4、exists 存在5、字符串函数&#xff08;重点&#xff09;6、数学函数7、日期函数 二、TCL语句1、创建用户2、赋予权限3、修改mysql允许远程登录 一、函数 1、ifnull 当前⾯的值是null的时候&#xff0c;使⽤后⾯的默认值 ifnull(字段…...

GPS在Linux下的使用(war driving的前置学习)

1.ls /dev/tty* 列出所有与 tty 相关的设备文件。这些设备文件通常对应终端设备 ttyUSB0是GPS端口 2.cat /dev/ttyUSB0 用于读取并显示连接到 /dev/ttyUSB0 串口设备发送的原始数据 这种是GPS定位不全的&#xff0c;要拿到更开阔的地方 这种是GPS定位全的 因为会持续输出…...

开发经验总结: 读写分离简单实现

背景 使用mysql的代理中间件&#xff0c;某些接口如果主从同步延迟大&#xff0c;容易出现逻辑问题。所以程序中没有直接使用这个中间件。 依赖程序逻辑&#xff0c;如果有一些接口可以走读库&#xff0c;需要一个可以显示指定读库的方式来连接读库&#xff0c;降低主库的压力…...

MySQL(面试题 - 同类型归纳面试题)

目录 一、MySQL 数据类型 1. 数据库存储日期格式时&#xff0c;如何考虑时区转换问题&#xff1f; 2. Blob和text有什么区别&#xff1f; 3. mysql里记录货币用什么字段类型比较好&#xff1f; 4. MySQL如何获取当前日期&#xff1f; 5. 你们数据库是否支持emoji表情存储&…...

【C++ Primer Plus习题】17.7

问题: 解答: #include <iostream> #include <vector> #include <string> #include <fstream> #include <algorithm>using namespace std;const int LIMIT 50;void ShowStr(const string& str); void GetStrs(ifstream& fin, vector<…...

vue3(整合版)

创建第一个vue项目 1.安装node.js cmd输入node查看是否安装成功 2.vscode开启一个终端&#xff0c;配置淘宝镜像 # 修改为淘宝镜像源 npm config set registry https://registry.npmmirror.com 输入如下命令创建第一个Vue项目 3.下载依赖&#xff0c;启动项目 访问5173端口 …...

复制他人 CSDN 文章到自己的博客

文章目录 0.前言步骤 0.前言 在复制别人文章发布时&#xff0c;记得表明转载哦 步骤 在需要复制的csdn 文章页面&#xff0c;打开浏览器开发者工具&#xff08;F12&#xff09;Ctrl F 查找"article_content"标签头 右键“Copy”->“Copy element”新建一个 tx…...

【算法——二分查找】

理论基础&#xff1a; 程序员面试经典题&#xff0c;二分搜索一个区间&#xff0c;区间查找 (LeetCode 34)_哔哩哔哩_bilibili 手把手带你撕出正确的二分法 | 二分查找法 | 二分搜索法 | LeetCode&#xff1a;704. 二分查找_哔哩哔哩_bilibili 这个是红蓝法&#xff0c;很牛…...

Cisco Packet Tracer的安装加汉化

这个工具学计算机网络的同学会用到 1.下载安装 网盘链接&#xff1a;https://pan.baidu.com/s/1CmnxAD9MkCtE7pc8Tjw0IA 提取码&#xff1a;frkb 点击第一个进行安装&#xff0c;按步骤来即可。 2.汉化 &#xff08;1&#xff09;复制chinese.ptl文件 &#xff08;2&…...

MMain函数定义为WinMain函数看port1632.h和pwin32.h文件

编译win2k3的源代码的时候有时候看到MMain函数 ..//public/sdk/inc/port1632.h #if defined(WIN16) /* ---------------- Maps to windows 3.0 and 3.1 16-bit APIs ----------------*/ #include "ptypes16.h" #include "pwin16.h" #include "plan16.…...

单词搜索问题(涉及递归等)

目录 一题目&#xff1a; 二思路解释&#xff1a; 三解答代码&#xff1a; 一题目&#xff1a; newcode题目链接&#xff1a; 单词搜索_牛客题霸_牛客网 二思路解释&#xff1a; 思路&#xff1a;个人理解是找到word中的第一个元素&#xff0c;然后去递归的上下左右查找&am…...

Redis的一些通用指令

首先我们需要先连接客户端服务器&#xff0c;此时我们需要通过redis-cli和redis服务器进行交互&#xff0c;输入ping来确保通路的流畅 &#xff08;一&#xff09;get和set redis中最核心的两个命令就是get和set&#xff0c;get就是根据key来取出对应value&#xff0c;set就是把…...

C++中vector类的使用

目录 1.vector类常用接口说明 1.1默认成员函数 1.1.1构造函数(constructor) 1.1.2 赋值运算符重载(operator()) 2. vector对象的访问及遍历操作(Iterators and Element access) 3.vector类对象的容量操作(Capacity) 4. vector类对象的修改及相关操作(Modifiers and Stri…...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

AI病理诊断七剑下天山,医疗未来触手可及

一、病理诊断困局&#xff1a;刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断"&#xff0c;医生需通过显微镜观察组织切片&#xff0c;在细胞迷宫中捕捉癌变信号。某省病理质控报告显示&#xff0c;基层医院误诊率达12%-15%&#xff0c;专家会诊…...

嵌入式学习笔记DAY33(网络编程——TCP)

一、网络架构 C/S &#xff08;client/server 客户端/服务器&#xff09;&#xff1a;由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序&#xff0c;负责提供用户界面和交互逻辑 &#xff0c;接收用户输入&#xff0c;向服务器发送请求&#xff0c;并展示服务…...

push [特殊字符] present

push &#x1f19a; present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中&#xff0c;push 和 present 是两种不同的视图控制器切换方式&#xff0c;它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...