Java面试——Nginx
优质博文:IT-BLOG-CN
一、为什么 Nginx可以采用异步非阻塞的方式来处理
看看一个请求的完整过程:请求过来,要建立连接,然后再接收数据,接收数据后,再发送数据。
二、Nginx 的优点
【1】速度更快:这表现在两个方面:一方面,在正常情况下,单次请求会得到更快的响应;另一方面,在高峰期(如有数以万计的并发请求),Nginx 可以比其他 Web服务器更快地响应请求。
【2】高扩展性,跨平台:Nginx 的设计极具扩展性,它完全是由多个不同功能、不同层次、不同类型且耦合度极低的模块组成。因此,当对某一个模块修复 Bug或进行升级时,可以专注于模块自身,无须在意其他。而且在 HTTP模块中,还设计了 HTTP过滤器模块:一个正常的 HTTP模块在处理完请求后,会有一串 HTTP过滤器模块对请求的结果进行再处理。这样,当我们开发一个新的 HTTP模块时,不但可以使用诸如 HTTP核心模块、events模块、log模块等不同层次或者不同类型的模块,还可以原封不动地复用大量已有的 HTTP过滤器模块。这种低耦合度的优秀设计,造就了 Nginx庞大的第三方模块,当然,公开的第三方模块也如官方发布的模块一样容易使用。
Nginx 的模块都是嵌入到二进制文件中执行的,无论官方发布的模块还是第三方模块都是如此。这使得第三方模块一样具备极其优秀的性能,充分利用 Nginx的高并发特性,因此,许多高流量的网站都倾向于开发符合自己业务特性的定制模块。
【3】高可靠性:用于反向代理,宕机的概率微乎其微。高可靠性是我们选择 Nginx的最基本条件,因为 Nginx的可靠性是大家有目共睹的,很多家高流量网站都在核心服务器上大规模使用 Nginx。Nginx 的高可靠性来自于其核心框架代码的优秀设计、模块设计的简单性;另外,官方提供的常用模块都非常稳定,每个 worker进程相对独立,master 进程在1个 worker进程出错时可以快速 “拉起” 新的 worker子进程提供服务。
【4】低内存消耗:一般情况下,10,000 个非活跃的 HTTP Keep-Alive 连接在 Nginx中仅消耗 2.5MB的内存,这是 Nginx支持高并发连接的基础。开启 10 个 Nginx 才占 150M 内存。
【5】单机支持10万以上的并发连接:这是一个非常重要的特性!随着互联网的迅猛发展和互联网用户数量的成倍增长,各大公司、网站都需要应付海量并发请求,一个能够在峰值期顶住 10万以上并发请求的 Server,无疑会得到大家的青睐。理论上,Nginx 支持的并发连接上限取决于内存,10万远未封顶。当然,能够及时地处理更多的并发请求,是与业务特点紧密相关的。
【6】热部署:Master 管理进程与 Worker工作进程的分离设计,使得 Nginx能够提供热部署功能,即可以在 7×24小时不间断服务的前提下,升级 Nginx的可执行文件。当然,它也支持不停止服务就更新配置项、更换日志文件等功能。
【7】最自由的 BSD许可协议:这是 Nginx可以快速发展的强大动力。BSD许可协议不只是允许用户免费使用 Nginx,它还允许用户在自己的项目中直接使用或修改 Nginx源码,然后发布。这吸引了无数开发者继续为 Nginx贡献自己的智慧。
以上七个特点当然不是 Nginx的全部,拥有无数个官方功能模块、第三方功能模块使得 Nginx能够满足绝大部分应用场景,这些功能模块间可以叠加以实现更加强大、复杂的功能,有些模块还支持 Nginx与 Perl、Lua等脚本语言集成工作,大大提高了开发效率。这些特点促使用户在寻找一个 Web服务器时更多考虑 Nginx。选择 Nginx的核心理由还是它能在支持高并发请求的同时保持高效的服务。
【8】高性能:处理 2-3 万并发连接数,官方监测能支持 5 万并发。
三、说说你在 Nginx中使用过的配置参数
当 Nginx安装完毕后,会有相应的安装目录,安装目录里的 nginx.confg为 Nginx的主配置文件,Nginx 主配置文件分为4部分,main(全局配置)、server(主机配置)、upstream(负载均衡服务器设置)以及 location(URL匹配特定位置的设置),这四者的关系是:server 继承main,location继承server,upstream 既不会继承其它设置也不会被继承。
【1】全局块:配置影响 Nginx全局的指令。一般有运行 Nginx服务器的用户组,Nginx进程 pid存放路径,日志存放路径,配置文件引入,允许生成 worker process 数等。
【2】events 块:配置影响 Nginx服务器或与用户的网络连接。有每个进程的最大连接数,选取哪种事件驱动模型处理连接请求,是否允许同时接受多个网路连接,开启多个网络连接序列化等。
【3】http 块:可以嵌套多个 server,配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置。如文件引入,mime-type定义,日志自定义,是否使用 sendfile传输文件,连接超时时间,单连接请求数等。
【4】server 块:配置虚拟主机的相关参数,一个 http中可以有多个 server。
【5】location 块:配置请求的路由,以及各种页面的处理情况。
四、Nginx 与 Apache 的区别
【1】Nginx 是基于事件的 Web 服务器(select 和 epoll 函数等),Apache 是基于流程的服务器;
【2】Nginx 是所有请求都由一个线程处理,Apache 是单线程处理单个请求;
【3】Nginx 在负载均衡方面表现较好,Apache 当流量到达进程的极限时,将拒绝新的连接;
【4】Nginx 可伸缩性和性能不依赖与硬件,Apache 依赖 CPU、内存等硬件组件;
【5】Nginx 在内存消耗和连接方面比较好,Apache 在内存消耗和连接方面并没有提高;
【6】Nginx 注重速度,Apache 注重功率;
【7】Nginx 避免了子进程的概率,Apache 是基于子进程的;
【8】Nginx 处理请求是异步非阻塞的,Apache 则是阻塞型的,在高并发下Nginx 能保持低资源低消耗高性能;
五、Nginx 负载均衡算法有哪些
Nginx 的 upstream 目前支持4种方式分配:
【1】轮询(默认):每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器宕掉,会自动提出;
【2】weight:指定轮询概率,weight 和访问比率成正比,用于后端服务器不均匀的情况;
【3】ip_hash:每个请求按访问 ip 的 hash 结果分配,这样每个访客固定访问一个后端服务器。可以解决session 的问题;
【4】fair(第三方):按照后端服务器的响应时间来分配请求,响应时间块的优先分配;
【5】url_hash(第三方):根据 url 的 hash 结果分配;
六、常见状态码
499:服务端处理时间过长,客户端主动关闭了连接。
【参考博客】
七、静态资源配置
静态资源的缓存服务器,比如在前后端分离的项目中,为了加速前端页面的响应速度,我们可以将前端的相关资源,例如html、js、css或者图片等放到 Nginx指定的目录下,访问的时候只需要通过 IP加路径就可以实现高效快速的访问,下面说说如何在 Windows下使用 Nginx作为静态资源服务器。
【1】修改 nginx.config配置文件;
【2】主要的配置参数如下,一些无关的参数我直接去掉了,注意,里面的 location可以配置多个,这样可以根据业务的需要指定相关的路径方便后续的运维和管理:
八、反向代理配置
反向代理服务器可以隐藏源服务器的存在和特征。它充当互联网云和 web服务器之间的中间层。这对于安全方面来说是很好的,特别是当您使用 web托管服务时。
【反向代理】
九、Nginx 进程模型
Nginx 默认采用多进程工作方式,Nginx启动后,会运行一个 master进程和多个 worker进程。其中 master充当整个进程组与用户的交互接口,同时对进程进行监护,管理 worker进程来实现重启服务、平滑升级、更换日志文件、配置文件实时生效等功能。worker用来处理基本的网络事件,worker 之间是平等的,他们共同竞争来处理来自客户端的请求。Nginx的进程模型如图所示:
master 对 work 进程采用信号进行控制
十、一个 Master 和多个 Woker 有好处
【1】可以使用 nginx –s reload 热部署,利用 nginx 进行热部署操作;
【2】每个 woker 是独立的进程,如果有其中的一个 woker 出现问题,其他 woker 独立的,继续进行争抢,实现请求过程,不会造成服务中断;
十二、设置多少个 woker 合适
worker 数和服务器的 cpu 数相等是最为适宜的;
十三、发送请求,占用了 woker 的几个连接数
当访问静态资源时占2个:请求一次,返回静态资源一次;
当访问非静态资源时占4个:nginx 需要将请求发送给 Tomcat 集群中的某个节点进行处理1次,同时Tomcat 处理完之后返回结果1次;
十四、Nginx 有一个 Master,有四个 Woker,每个 Woker 支持最大的连接数 1024,支持的最大并发数是多少
普通的静态访问最大并发数是: worker_connections * worker_processes /2,而如果是 HTTP 作为反向代理来说,最大并发数量应该是 worker_connections * worker_processes/4。
十五、Nginx 工作原理
Nginx 由内核和模块组成。Nginx 本身做的工作实际很少,当它接到一个 HTTP请求时,它仅仅是通过查找配置文件将此次请求映射到一个 location block,而此 location中所配置的各个指令则会启动不同的模块去完成工作,因此模块可以看做 Nginx真正的劳动工作者。通常一个 location中的指令会涉及一个 handler模块和多个 filter模块(当然,多个 location可以复用同一个模块)。handler 模块负责处理请求,完成响应内容的生成,而 filter模块对响应内容进行处理。用户根据自己的需要开发的模块都属于第三方模块。正是有了这么多模块的支撑,Nginx 的功能才会如此强大。Nginx 的模块从结构上分为核心模块、基础模块和第三方模块:
【1】核心模块:HTTP模块、EVENT模块和MAIL模块;
【2】基础模块:HTTP Access模块、HTTP FastCGI模块、HTTP Proxy模块和HTTP Rewrite模块;
【3】第三方模块:HTTP Upstream Request Hash模块、Notice模块和HTTP Access Key模块。
Nginx 的模块从功能上分为如下三类:
【1】Handlers(处理器模块)。此类模块直接处理请求,并进行输出内容和修改 headers信息等操作。Handlers处理器模块一般只能有一个;
【2】Filters (过滤器模块)。此类模块主要对其它处理器模块输出的内容进行修改操作,最后由 Nginx输出;
【3】Proxies (代理类模块)。此类模块是 Nginx的 HTTP Upstream之类的模块,这些模块主要与后端一些服务比如 FastCGI等进行交互,实现服务代理和负载均衡等功能。
十六、负载均衡配置
【博客连接】:https://blog.csdn.net/zhengzhaoyang122/article/details/94287448
十七、虚拟主机配置
【博客连接】:https://blog.csdn.net/zhengzhaoyang122/article/details/93793377
十八、Nginx 常用命令
【1】启动 nginx:
【2】停止 nginx -s stop 或 nginx -s quit ;
【3】重载配置 ./sbin/nginx -s reload(平滑重启) 或 service nginx reload ;
【4】重载指定配置文件, -c :使用指定的配置文件而不是 conf 目录下的 nginx.conf ;
【5】查看 nginx 版本 nginx -v ;
【6】检查配置文件是否正确 nginx -t ;
【7】显示帮助信息 nginx -h ;
十九、请解释什么是 C10K
问题
C10K
问题是指无法同时处理大量客户端(10,000)的网络套接字。
二十、Nginx 如何处理 Http 请求
【1】首先,Nginx 在启动时,会解析配置文件,得到需要监听的端口与 IP 地址,然后在 Nginx 的 Master 进程里面先初始化好这个监控的 Socket(创建 Socket,设置 addr、reuse 等选项,绑定到指定的 ip 地址端口,再 listen 监听)。
【2】然后,再 fork(一个现有进程可以调用 fork 函数创建一个新进程。由 fork 创建的新进程被称为子进程 )出多个子进程出来。
【3】之后,子进程会竞争 accept 新的连接。此时,客户端就可以向 nginx 发起连接了。当客户端与nginx进行三次握手,与 nginx 建立好一个连接后。此时,某一个子进程会 accept 成功,得到这个建立好的连接的 Socket ,然后创建 nginx 对连接的封装,即 ngx_connection_t 结构体。
【4】接着,设置读写事件处理函数,并添加读写事件来与客户端进行数据的交换。这里,还是有一些逻辑,继续在 「Nginx 是如何实现高并发的?」 问题中来看。
【5】Nginx 或客户端来主动关掉连接,到此,一个连接就寿终正寝了。
【6】最后,Nginx 或客户端来主动关掉连接,到此,一个连接就寿终正寝了。
二十一、fastcgi 与 cgi 的区别
FastCGI 是一个可伸缩地、高速地在 HTTP server和动态脚本语言间通信的接口。多数流行的 HTTP server都支持FastCGI,包括 Apache、Nginx 和 lighttpd 等。同时,FastCGI 也被许多脚本语言支持,其中就有 PHP。
FastCGI 是从 CGI发展改进而来的。传统 CGI接口方式的主要缺点是性能很差,因为每次 HTTP服务器遇到动态程序时都需要重新启动脚本解析器来执行解析,然后将结果返回给 HTTP服务器。这在处理高并发访问时几乎是不可用的。另外传统的 CGI接口方式安全性也很差,现在已经很少使用了。
FastCGI 接口方式采用 C/S结构,可以将 HTTP服务器和脚本解析服务器分开,同时在脚本解析服务器上启动一个或者多个脚本解析守护进程。当 HTTP服务器每次遇到动态程序时,可以将其直接交付给 FastCGI进程来执行,然后将得到的结果返回给浏览器。这种方式可以让 HTTP服务器专一地处理静态请求或者将动态脚本服务器的结果返回给客户端,这在很大程度上提高了整个应用系统的性能。
【1】cgi:web 服务器会根据请求的内容,然后会 fork 一个新进程来运行外部 c 程序(或 perl 脚本…), 这个进程会把处理完的数据返回给 web 服务器,最后 web 服务器把内容发送给用户,刚才 fork 的进程也随之退出。如果下次用户还请求改动态脚本,那么 web 服务器又再次 fork 一个新进程,周而复始的进行。
【2】fastcgi:web 服务器收到一个请求时,他不会重新 fork 一个进程(因为这个进程在 web 服务器启动时就开启了,而且不会退出),web 服务器直接把内容传递给这个进程(进程间通信,但 fastcgi 使用了别的方式,tcp 方式通信),这个进程收到请求后进行处理,把结果返回给 web 服务器,最后自己接着等待下一个请求的到来,而不是退出。
综上,差别在于是否重复 fork 进程,处理请求。
二十二、Nginx 是如何实现高并发的
一个主进程,多个工作进程,每个工作进程可以处理多个请求,每进来一个 request,会有一个 worker进程去处理。但不是全程的处理,处理到可能发生阻塞的地方,比如向上游(后端)服务器转发 request,并等待请求返回。那么,这个处理的 worker继续处理其他请求,而一旦上游服务器返回了,就会触发这个事件,worker才会来接手,这个 request才会接着往下走。由于web server 的工作性质决定了每个 request的大部份生命都是在网络传输中,实际上花费在 server机器上的时间片不多。这是几个进程就解决高并发的秘密所在。即 @skoo所说的 webserver刚好属于网络 IO密集型应用,不算是计算密集型。
二十三、为什么不使用多线程
Apache:创建多个进程或线程,而每个进程或线程都会为其分配 cpu和内存(线程要比进程小的多,所以worker支持比perfork高的并发),并发过大会榨干服务器资源。
Nginx:采用单线程来异步非阻塞处理请求(管理员可以配置 Nginx主进程的工作进程的数量)(epoll),不会为每个请求分配 CPU和内存资源,节省了大量资源,同时也减少了大量的 CPU的上下文切换。所以才使得 Nginx支持更高的并发。
二十四、为什么 Nginx性能这么高
得益于它的事件处理机制:异步非阻塞事件处理机制:运用了 epoll模型,提供了一个队列,排队解决;
二十五、内存池的设计
为了减少避免出现内存碎片、减少向操作系统申请内存的次数、降低各个模块的开发复杂度,Nginx采用了简单的内存池(统一申请,统一释放)。比如为每个 http请求分配一个内存池,请求结束时销毁整个内存池。
二十六、平台无关的代码实现
在核心代码都使用了与操作系统无关的代码实现,在与操作系统相关的系统调用上则分别针对各个操作系统都有独立实现,这最终造就了 Nginx的可移植性。
二十七、Nginx 进程间的通信
工作进程是由主进程生成的,主进程使用 fork()函数,在 Nginx服务器启动过程中主进程根据配置文件决定启动工作进程的数量,然后建立一张全局的工作表用于存放当前未退出的所有的工作进程,主进程生成工作进程后会将新生成的工作进程加入到工作进程表中,并建立一个单向的管道并将其传递给工作进程,该管道与普通的管道不同,它是由主进程指向工作进程的单项通道,包含了主进程想工作进程发出的指令、工作进程ID、工作进程在工作进程表中的索引和必要的文件描述符等信息。
主进程与外界通过信号机制进行通信,当接收到需要处理的信号时,它通过管道向相关的工作进程发送正确的指令,每个工作进程都有能力捕获管道中的可读事件,当管道中有可读事件的时候,工作进程就会从管道中读取并解析指令,然后采取相应的执行动作,这样就完成了主进程与工作进程的交互。
二十八、事件驱动框架
Nginx事件驱动框架:所谓事件驱动架构,简单来说,就是由一些事件发生源来产生事件,由一个或多个事件收集器(epolld等)来收集、分发事件,然后许多事件处理器会注册自己感兴趣的事件,同时会“消费”这些事件。Nginx不会使用进程或线程作为事件消费者,只能是某个模块,当前进程调用模块。
传统 web服务器(如Apache)的,所谓事件局限在 TCP连接建立、关闭上,其他读写都不在是事件驱动,这时会退化成按序执行每个操作的批处理模式,这样每个请求在连接建立后都将始终占用系统资源,直到连接关闭才会释放资源。大大浪费了内存、cpu等资源。并且把一个进程或线程作为事件消费者。传统 web服务器与 Nginx间重要差别:前者每个事件消费者独占一个进程资源,后者只是被事件分发者进程短期调用而已。
二十九、请求的多阶段异步处理
请求的多阶段异步处理只能基于事件驱动框架实现,就是把一个请求的处理过程按照事件的触发方式分为多个阶段,每个阶段都可以有事件收集、分发器(epoll等)来触发。比如一个 http请求可以分为七个阶段。
三十、在 Nginx中,请说明 Rewrite模块里 break和 last的区别
官方文档的定义如下:
【1】last:停止执行当前这一轮的 ngx_http_rewrite_module指令集,然后查找匹配改变后 URI的新 location;
【2】break:停止执行当前这一轮的 ngx_http_rewrite_module指令集;
【举个例子】:如下
使用 break会匹配两次 URL,如果没有满足项,就会停止匹配下面的 location,直接发起请求 www.xxx.com/test2.txt,由于不存在文件 test2.txt,则会直接显示404。
使用 last的话,会继续搜索下面是否有符合条件(符合重写后的 /test2.txt请求)的 location,匹配十次,如果十次没有得到的结果,那么就跟 break一样了。返回上面的例子,/test2.txt 刚好与面 location的条件对应上了,进入花括号{}里面的代码执行,这里会返回500。
三十一、请列举 Nginx服务器的最佳用途
Nginx 服务器的最佳用法是在网络上部署动态 HTTP内容,使用 SCGI、WSGI应用程序服务器、用于脚本的 FastCGI处理程序。它还可以作为负载均衡器。
三十二、Nginx 中 nginx.conf 配置文件的优化
三十三、Nginx 内核参数优化
三十四、利用 TCMalloc优化 Nginx的性能
三十五、编译安装过程优化
三十六、Nginx 支持的事件模型
Nginx 支持如下处理连接的方法(I/O复用方法),这些方法可以通过 use指令指定。
【1】select– 标准方法。 如果当前平台没有更有效的方法,它是编译时默认的方法。你可以使用配置参数 –with-select_module 和 –without-select_module 来启用或禁用这个模块。
【2】poll– 标准方法。 如果当前平台没有更有效的方法,它是编译时默认的方法。你可以使用配置参数 –with-poll_module 和 –without-poll_module 来启用或禁用这个模块。
【3】kqueue– 高效的方法,使用于 FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0 和 MacOS X. 使用双处理器的MacOS X系统使用kqueue可能会造成内核崩溃。
【4】epoll – 高效的方法,使用于Linux内核2.6版本及以后的系统。在某些发行版本中,如SuSE 8.2, 有让2.4版本的内核支持epoll的补丁。
【5】rtsig – 可执行的实时信号,使用于Linux内核版本2.2.19以后的系统。默认情况下整个系统中不能出现大于1024个POSIX实时(排队)信号。这种情况 对于高负载的服务器来说是低效的;所以有必要通过调节内核参数 /proc/sys/kernel/rtsig-max 来增加队列的大小。可是从Linux内核版本2.6.6-mm2开始, 这个参数就不再使用了,并且对于每个进程有一个独立的信号队列,这个队列的大小可以用 RLIMIT_SIGPENDING 参数调节。当这个队列过于拥塞,nginx就放弃它并且开始使用 poll 方法来处理连接直到恢复正常。
【6】/dev/poll – 高效的方法,使用于 Solaris 7 11/99+, HP/UX 11.22+ (eventport), IRIX 6.5.15+ 和 Tru64 UNIX 5.1A+.
【7】eventport – 高效的方法,使用于 Solaris 10. 为了防止出现内核崩溃的问题, 有必要安装这个 安全补丁。
三十七、Nginx+FastCGI运行原理
Nginx 不支持对外部程序的直接调用或者解析,所有的外部程序(包括 PHP)必须通过 FastCGI接口来调用。FastCGI 接口在Linux 下是 socket(这个socket可以是文件socket,也可以是ip socket)。
wrapper:为了调用 CGI程序,还需要一个 FastCGI的 wrapper(wrapper可以理解为用于启动另一个程序的程序),这个wrapper 绑定在某个固定 socket上,如端口或者文件socket。当 Nginx将CGI请求发送给这个 socket的时候,通过 FastCGI接口,wrapper 接收到请求,然后 Fork(派生)出一个新的线程,这个线程调用解释器或者外部程序处理脚本并读取返回数据;接着,wrapper 再将返回的数据通过 FastCGI接口,沿着固定的 socket传递给 Nginx;最后,Nginx 将返回的数据(html页面或者图片)发送给客户端。这就是 Nginx+FastCGI的整个运作过程,如下图所示。
三十八、Nginx多进程事件模型:异步非阻塞
虽然 Nginx采用多 worker的方式来处理请求,每个 worker里面只有一个主线程,那能够处理的并发数很有限啊,多少个 worker就能处理多少个并发,何来高并发呢?非也,这就是 Nginx的高明之处,Nginx采用了异步非阻塞的方式来处理请求,也就是说,Nginx是可以同时处理成千上万个请求的。一个 worker进程可以同时处理的请求数只受限于内存大小,而且在架构设计上,不同的 worker进程之间处理并发请求时几乎没有同步锁的限制,worker进程通常不会进入睡眠状态,因此,当 Nginx上的进程数与 CPU核心数相等时(最好每一个worker进程都绑定特定的CPU核心),进程间切换的代价是最小的。
而 Apache的常用工作方式(Apache也有异步非阻塞版本,但因其与自带某些模块冲突,所以不常用),每个进程在一个时刻只处理一个请求,因此,当并发数上到几千时,就同时有几千的进程在处理请求了。这对操作系统来说,是个不小的挑战,进程带来的内存占用非常大,进程的上下文切换带来的cpu开销很大,自然性能就上不去了,而这些开销完全是没有意义的。
三十九、为什么 Nginx可以采用异步非阻塞的方式来处理
看看一个请求的完整过程:请求过来,要建立连接,然后再接收数据,接收数据后,再发送数据。
具体到系统底层,就是读写事件,而当读写事件没有准备好时,必然不可操作,如果不用非阻塞的方式来调用,那就得阻塞调用了,事件没有准备好,那就只能等了,等事件准备好了,你再继续吧。阻塞调用会进入内核等待,cpu就会让出去给别人用了,对单线程的worker来说,显然不合适,当网络事件越多时,大家都在等待呢,cpu空闲下来没人用,cpu利用率自然上不去了,更别谈高并发了。好吧,你说加进程数,这跟 apache的线程模型有什么区别,注意,别增加无谓的上下文切换。所以,在nginx里面,最忌讳阻塞的系统调用了。不要阻塞,那就非阻塞喽。非阻塞就是,事件没有准备好,马上返回EAGAIN,告诉你,事件还没准备好呢,你慌什么,过会再来吧。好吧,你过一会,再来检查一下事件,直到事件准备好了为止,在这期间,你就可以先去做其它事情,然后再来看看事件好了没。虽然不阻塞了,但你得不时地过来检查一下事件的状态,你可以做更多的事情了,但带来的开销也是不小的。