问下,u3d和ue44e 哪个自学快一些,会C#、java和jquery等一些语言,以前没接触过游戏开发,只是个人感兴趣

没基础学c#
多长时间能达到工作的水平_c#吧_百度贴吧
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&签到排名:今日本吧第个签到,本吧因你更精彩,明天继续来努力!
本吧签到人数:0成为超级会员,使用一键签到本月漏签0次!成为超级会员,赠送8张补签卡连续签到:天&&累计签到:天超级会员单次开通12个月以上,赠送连续签到卡3张
关注:121,185贴子:
没基础学c#
多长时间能达到工作的水平收藏
南京网博软件编程培训机构,c#编程学习好去处!校企合作办学,10年之内全部包就业!网博IT培训,全程小班非视频教学,零基础也能学得会!支持先就业后付款,学费无忧!
我们学BS的,不到一年就可以工作了,不过我选择继续学
分什么工作
有的1年 有的7年
学了两个月,各种不会,最大的感觉就是经验最重要
c#算是比较简单的了
半年吧,能工作,但还要在工作中继续学习
对于想学习软件开发的人来讲,您肯定对软件开发有了一些了解,但您在决定学习之前, 肯定也会遇到一个问题,那就是学什么语言?因为您看到身边的朋友或同学,有的学.NET,有的学java, 有的学PHP,有的学C、C++等等,而往往初学者对这些开发语言又不能很好的区别,究竟自己应该选什么开发语言呢? 我想肯定会让好多初学者感到疑惑,下面我就给大家分享一下我的体会和建议,希望能给您提供一些帮助。 开发语言的专业方向比较强,应该正确划分不同开发语言所属的专业方向。现在对于大多数的学习者而言, 开发语言基本可以划分两个方向:第一,硬件底层开发语言。这类语言一般是汇编语言、C语言、C++等,当然C++相对于前两种开发语言更加高级,并且应用范围更加广泛。比如, 我们的计算机操作系统开发,我们所用的家电设备的控制、手机的底层软件、汽车的行车电脑,以及各类电子电器设备的运行等等 ,都需要这些底层软件支持,一般我们把从事这方面的工作的开发称之为“嵌入式开发”,因为这些程序一般都固化在硬件设备里面 ,一旦开发完毕,不会经常修改,当然,也会适当升级。 今天我们不具体谈论如何学习这些语言,我只想告诉大家,这些主流的底层开发语言学习者一般都有比较好的硬件基础, 因为这个开发语言往往和硬件关系非常大,它的开发好多情况是直接依赖于硬件设备的,所以,如果您不是这方面的专业人才, 我不建议您学习,因为那样的话,学习成本会非常高,难度会非常大,即使入门了,想深入的话,难度也非常大。 这些语言一般都是大学里面的专业基础课,好多人都略知一二,但做开发的确很少。但是,这方面的人才却很重要, 薪水也很高,因为它的学习成本高,经验也非常重要。第二、业务应用层开发语言。这类开发语言主流的有.NET、Java、PHP等。之所以把这些语言称之为“业务应用层”开发语言,是因为这些语言开发的软件一般都是直接和我们使用者打交道的,是为了提高我们的工作效率或实现某种信息交互(比如电子商务网站等类型的应用)而开发的。这些开发语言也是现在大多数软件开发者在工作中使用的,需求潜力巨大,学习成本低,是我们大多从业者需要学习的。 那么如何正确的区分这三类语言,并选择一个适合自己的开发语言来学习呢? 1. 首先说java语言,因为这个语言出现的比较早,企业使用的也很多,现在的应用范围也是非常广泛的。 Java语言在web开发领域具有很强的竞争力,这种竞争力源于本身语言的强大性。目前,Java2平台有3个版本, 它们是适用于小型设备和智能卡的Java 2平台Micro版(Java 2 Platform Micro Edition,Java ME)、 适用于桌面系统的Java 2平台标准版(Java 2 Platform Standard Edition,Java SE)、 适用于创建服务器应用程序和服务的Java 2平台企业版(Java 2 Platform Enterprise Edition,Java EE)。 从上面三个版本相信大家能看出java语言在桌面系统开发、web开发、移动设备开发等都被广泛使用, 但web和移动设备开发更是java的强项,java语言之所以被广泛应用还有另外一个重要特点就是开源性, 这样全世界的开发者都可以为java语言奉献自己的力量,使得java框架的类型非常繁多,并且更新速度快。 由于java是开源框架,所以企业在使用的时候成本几乎可以忽略不计。最后一点,java语言还具备很好的跨平台性, 也就是不管是在windows平台还是linux、unix等主流平台,java程序都会很轻松的部署和维护,这一点尤其受企业的青睐。 java语言还有好多优点,这里我们就不多说了,当然任何语言也会有自己的不足,java语言应用非常广泛,但学习成本比较高, 因为是开源框架,需要开发者时刻关注版本的变化,开发者在轻松享受别人贡献的同时,也带来程序调试的困难。 2. 下面我们简单说一说PHP,现在好多企业网站也都是用PHP做的,如果您看到浏览器地址栏里面最后结尾处有.php, 那么该网站一定有php网页。那么PHP有哪些优点和不足呢?下面我们看一下: PHP和java语言以及.NET平台开发语言不同,它是将程序嵌入到HTML文档中去执行,而java和.NET平台的开发语言 现在都是前台和后台分开设计和编写,PHP现在的黄金搭档是LAMP,也就是linux平台+Apache服务器+MySQL数据库+ PHP语言,如果用户使用这种组合形式开发出的网站,除了人工成本以外,几乎可以不支付其他额外产品费用,同时,由于PHP 的跨平台性和java一样方便,同样也深受企业的喜爱,这几年PHP也非常流行,在全国知名的淘宝网平台上面,就有很多PHP 网页,当然淘宝网的设计绝不是一种开发语言能够完成的。 PHP的语法也非常简洁,学习起来也比较容易,但PHP除了web应用外,在其他领域几乎看不到它的身影, 所以PHP语言的使用领域比较单一,同时,因为PHP程序编写的时候前台和后台代码是混编在一起的, 而java和.NET平台在设计的时候是极力避免这种情况的,毕竟混编在一起会使得程序的修改和维护带来一定麻烦。 3. 最后我们谈谈.NET,.NET(英语读作dot net)我们习惯于读作“点儿”NET,其实这是不正确的读法, 但是大家都习惯了也无所谓,在正式场合还是希望大家按照英语的标准读音使用,别的少说,我们看看.NET是怎么回事。
首先,我们要分清几个概念:.NET、C#、VB、VC++等,虽然这些是大家经常说的,但对于初学者而言却经常弄不清楚。 .NET和java一样,它是一个平台的概念,但.NET和java又很不一样,原因是java平台里面就一种java语言, 而.NET则提供了若干种语言,C#是伴随着.NET平台出现而量身定做的平台语言,在.NET平台之前是没有的, 说到这里大家就应该明白了,.NET是程序开发和运行的平台,在这个平台基础之上开发者可以选择自己喜欢的开发语言, 比如C#、VB.NET、VC++.NET等,C#语言继承了C、C++和java语言的优点,重新整合设计,所以C#语言非常容易学, 其语法结构和java及C++非常相似,尤其是java,因为都是完全的面向对象语言,两者语言特性几乎都能吻合在一起。 而VB.NET和VC++是在以前非.NET平台的时候就有了,而且当时VB的程序员是一统天下,当微软推出.NET平台的时候, 肯定会把VB的程序员和VC++的程序员吸引过来,所以.NET平台下的VB.NET和VC++.NET,是平台的移植, 这样在.NET平台下的C#、VB.NET、VC++.NET三种主流语言并驾齐驱,您可以任意选择,同时,这三种语言的开发者, 在开发同一个项目的时候,可以完全根据需要选择语言类型,不同语言开发的模块,可以直接使用,而不像其他语言那样, 如果一个模块使用了其他语言编写,要想集成到自己的项目中会变得非常麻烦,而微软的.NET平台对多语言编程简直就是 一个彻底的颠覆!这也是.NET平台大一个重要特点之一:跨语言,而java和PHP是跨平台,.NET也可以实现跨平台,但 是在linux和unix平台上部署的时候相对麻烦,这也是它的一个小小不足,但是毕竟微软的windows平台在全世界是占有 率最高的,所以主流的平台依然是windows,这一点是不可否认的。 谈到这里,大家也许要问了,每个语言都有自己的优缺点,那我究竟该选择哪一个呢?好,那我就把我的想法和大家谈一下, 我个人建议初学者学习.NET平台的C#语言。原因如下:(1).NET平台现在的版本是2.0、3.5、4.0,从2.0开始就是一个非常成熟的平台,后面都是完全继承前面的, 这个请大家放心。微软在世界的地位是人人皆知的,有这么强大的公司做支持,大家完全可以不用担心产品的使用问题。(2)C#语言语法简洁、完全的面向对象特性,当然最关键的是和.NET平台同时推出的Visual Studio开发工具, 现在发展到了2010版本,这个开发工具的出现令世界震惊,因为程序的编写、编译、调试、发布于一体,而且最关键的是这 个开发工具的调试能力是如此强大,当您编写的程序语句有语法或其他错的时候,编译会直接给你指向错误的语句,并且告诉 您这是怎么错误,并适当给出解决方法,这一点对于初学者而言是相当关键的,初学者在学习的时候最害怕的就是出现错误不 知道从哪里修改,而VS这个开发工具的使用让初学者完全不必担心错误解决问题,就这一点是其他任何开发语言的开发工具 都无法比拟的,就凭这一点初学者您有什么不能完全接受C#呢?(3)强大的类库、MSDN帮助文档和唾手可得的各种控件无疑给开发者又增加了很多乐趣,当然这种乐趣是基于开发的 高效率而言的,尤其是开发桌面应用程序,强大的控件,可以让开发者节省约70%的代码量,就这一点其他开发语言更是无 法相比的,试问,不管你是初学者还是有经验的高手,难道你在开发中和效率过不去吗?如果C#能用一天的时间搞定,你非 得选择其他语言用一周去搞定吗?当然也有好多人说.NET就是拖放控件,我也遇到过,但凡跟我说这样话的人都被我扁的一 文不值,我不想说别的,只想告诉大家,说这些话的人是因为他们根本就没真正做过.NET开发,或者根本就不了解.NET。(4)我建议大家学.NET,不是说其他语言不好,刚开始我说java和php一直说他们的优点,我是想告诉大家, 开发语言之间没有好坏之分,主流语言都是非常棒的,而我们今天要谈的是对“初学者”而言,记住是“初学者”, 因为您还不懂开发语言,而C#的特点是非常适合初学者的,您可以学习很短的一段时间就能做项目,而java语言你要学习很 多框架,框架的使用对于初学者而言还是有难度的,并且程序的调试有时候真的就足以让初学者头疼的连吃药都不管事, 当然我这个有点夸张,呵呵。而php呢,虽说非常强大,但应用领域单一,而且代码混编,看不出您的个人真实水平,因为 我们要学习开发语言之外的“面向对象思想”,PHP做为面向对象语言,去无法很好给初学者体现出这一点。而当您学完C# 以后,等到工作了,想学java了,那会变得非常轻松,因为“面向对象”思想都是一样的,您只需要熟悉一下语法的区别、 类库的区别和框架的使用就可以了,如果您学C#用了一年搞定,那么再学java两个月就可以搞定了。而PHP呢,我只想告诉 大家,如果您真的在工作用到了,必须得学的时候,再看看吧。最后,用一句话概括一下,开发语言没有优劣,初学者选择入门语言却非常重要,学习.NET平台下的C#语言, 您将会在学习的过程中其乐无穷!
一小时速成班
c#编程学习0元入学,免费试听,0基础小班授课!1对1就业跟踪服务!职坐标学的是紧跟企业需求的职坐标c#编程学习实战项目,1对1答疑辅导,,选职坐标0基础也可以拿高薪!
写的非常好,受教了。
学了几年的C++来该行…………
认真点 大半年就可以
刚开始真的很简单,后面难得要死、
学了三个半月后开始找工作,0基础
你先去看看。。C#的分支,确定一个方向吧。不然一年你估计啥都不会。。。。还有要做的好,先去看点数据库的书吧。。。。。
有java、c++基础,理解oo思想,有开发经验一个月吧,别说那些只会拖控件的人会c#。
刚开始学c# 感觉很难,而且自己敲代码敲的很慢,老师上课就讲了点,就叫我们做,作业不会做。求各位给点意见啊??
kunkunxuanxuan你讲得太好了,让我这种初学者明白了很多,受教了,也粉你!加你QQ可以吗,以后还请多指点
希望能认识你
说的真的太好了 我开始以为是什么黄土哥之类的复制粘贴 看完才觉得你是个大神 说实话 对于初学者来说 这些知识就应该早点让他们知道
留下小腳印从0开始学,看看自己能不能坚持下去
快得很~只要有牛逼的心~
现在VR好就就业吗? 我是0基础,这两天看了C#的视频,才几天时间,是不是学习VR就得学C#?
我学了俩星期
登录百度帐号JAVA:飞机大战游戏,让自己的飞机打出子弹,求指导
[问题点数:100分]
本版专家分:0
CSDN今日推荐
匿名用户不能发表回复!|
其他相关推荐
import tkinter
root_window = tkinter.Tk()
root_window.title(&盖世大战&)#固定窗口大小
root_window.resizable(width=False, height=False)
window_canvas = tkinter.Canvas(root_window,
编写python打飞机小游戏图片资源
编写pygame打飞机小游戏图片资源
自己做了一个简单的打飞机游戏,比较粗糙,下面把子弹和敌人的产生,移动,碰撞的代码拿出来给大家参考参考
功能齐全的简单打飞机游戏,声音,粒子特效,敌人的产生。
我们现在编写子弹类,我们设计子弹为了通用一点,敌人飞机向下发射子弹,英雄飞机向屏幕上方发射子弹,那我们就在创建子弹的时候,设置传递一个参数,根据参数来选择子的子弹的图片和子弹移动的方向。
这里注意一点,pygame.image.load()图片之后,我们可以通过图片对象的get_rect()方法来获得图片的矩形(矩形应该包括该图片在窗口里的x和y坐标,以及其宽和高),但是矩形的x和y坐标始终是(
欢迎来到unity学习、unity培训、unity企业培训教育专区,这里有很多U3D资源、U3D培训视频、U3D教程、U3D常见问题、U3D项目源码,我们致力于打造业内unity3d培训、学习第一品牌。
今天我们学习了Unity3D中的飞机发射子弹。
效果图(在右下角这个是自己的飞机,它可以前后左右移动,也可以发射子弹。)
1、添加在飞机模
子弹的位置与自己的敌机位置有关,大家可以随意设置不同样式的子弹,比如双排子弹,三排子弹,实现不同的效果,通过改变刷新的频率和设置他的速率效果都不一样,
看看下面我设置的几种简单的子弹。
package com.example.
import java.util.R
import android.content.res.R
Android飞机大战所需要声音文件
我的飞机发射子弹的声音
boss飞机发射子弹的声音
我方飞机的子弹和敌机子弹都在这个类中产生。将子弹专门设计成一个类,主要是为了方便扩展。之后如果想更换我方飞机子弹或者是敌机子弹,都会很方便。
类的功能很直观,就是添加子弹、移除子弹
void bindEnemyManager(EnemyManager* enemyManager);
void BeginBulletShoot(float dt = 0.0f); // 开启子
序言作为一个android开发者,时常想开发一个小游戏娱乐一下大家,今天就说说,我是怎么样一天写出一个简单的“飞机大战”的.体验地址:http://www.wandoujia.com/apps/edu.njupt.zhb.planegame游戏分析玩过“飞机大战”游戏的都知道,飞机大战中的主要“角色”有:1.玩家飞机2.敌方飞机3.玩家飞机发送的子弹4.敌方Boss飞机发送的子弹我们需要控制的有:本人是学javaWeb想转游戏开发方向,望大家指导
[问题点数:40分]
本版专家分:0
结帖率 71.43%
CSDN今日推荐
本版专家分:0
2013年2月 多媒体/设计/Flash/Silverlight 开发大版内专家分月排行榜第一2013年1月 多媒体/设计/Flash/Silverlight 开发大版内专家分月排行榜第一
2013年1月 C/C++大版内专家分月排行榜第二
本版专家分:0
本版专家分:0
本版专家分:0
2012年8月 专题开发/技术/项目大版内专家分月排行榜第二
本版专家分:0
本版专家分:0
本版专家分:0
本版专家分:0
本版专家分:0
匿名用户不能发表回复!|
其他相关推荐295 条评论分享收藏感谢收起Asp.Net,WebForm,以及MVC开发。值得一提的是Silverlight(银光技术)是类似于Flash的一种网页组件,但不同的是Sliverlight开发出来的是整个页面,而不是Flash一样的嵌入插件。它的学习路线是WPF的子集,由于它过于消耗流量,已经被绝大部分企业弃用。现在的主流方向是MVC。3 题主提到数据库,无论你开发什么都必须要使用数据库,.Net系统经常与Sqlserver一起使用。4 .Net 还可以用来开发安卓的后台,主要使用Webservice。还可以做Windows服务,比如我在公司的OA服务器上偷偷安装了个自启动服务,功能是每分钟检查一次服务器时间,把8:30到8:35的时间定格到8:29的随机某秒,把17:55到18:00的时间定格到18:01的随机某秒,其他时间正常,这样就可以迟到5分钟上班,提前5分钟下班。再来说说我的经历。六年前我开始使用WinForm,确实出活很快,但后来领导嫌我界面太丑,于是我一开始使用了WinForm的一个皮肤插件,发现它的可定制化程度太低,然后发现WPF竟然可以做也如此炫丽的东西,于是就开始废寝忘食地研究。当然在数据库方面,随着数据量的增长,要维护的数据库实例的增多,为了提高性能我甚至研究过数据库文件的组织格式,当然没什么卵用,优化主要来自于设计,像索引,表分层,多库多机,无所不用。后来微信火了,领导说要跟上时代,所以我又跑去搞微信,做了个IIS托管的C#后台,顺便把以前的客户端搞成了MVC网页版,这样我们也算开始进军BS架构,与时代接轨了。总结如下: 这三样技术是开发主流: WPF,MVC,数据库,值得你花费大部分精力。同时要熟练掌握TCP通信,WCF,Webservice,这三样比较简单,等你做几个项目自然就会了。最后一条: 你要学什么技术不是你说了算,而是CTO说了算。我还临时做过Java, php, delphi的项目,第一天CTO一动员,第二天就开始干活,学习?学个毛毛,先交活再说。赞同 6117 条评论分享收藏感谢收起&p&没人说说咸海中间那个岛吗?生化危机BIOHAZARD这个单词鼎鼎大名啊!&/p&&p&挖个坑吧&/p&&hr&&p&半个月后,我终于来填坑了!&/p&&p&本文内容收集整理自网络,其中大部分内容来自原作者&a class=&member_mention& href=&//www.zhihu.com/people/9c659e319ba8ec59abe5eb633ccc99c7& data-hash=&9c659e319ba8ec59abe5eb633ccc99c7& data-hovercard=&p$b$9c659e319ba8ec59abe5eb633ccc99c7&&@眠眠&/a& 的 &a href=&https://zhuanlan.zhihu.com/mianmian& class=&internal&&眠眠冰室&/a&&/p&&p&本文有大量的文字和图片内容,请谨慎阅读。&/p&&p&&br&&/p&&p&&b&一、斯维尔德罗夫斯克&/b&&/p&&p&&br&&/p&&p&在《生化危机3》的结局,政府为了遏制浣熊镇的那场可怕事故,最终选择的方案是用一枚核弹彻底毁灭了这个城市。然而在现实里,这种办法可能并不一定真的像游戏中那么简单有效,一了百了。&/p&&p&这起由炭疽引发的大规模炭疽热,也被称为历史上的 “生物切尔诺贝利”。&/p&&p&1979年,一份由苏联流亡者经营的小报登了一条惊人的消息:斯维尔德洛夫斯克州首府叶卡捷琳堡的一家军工厂发生爆炸,泄露出的致命细菌造成上千人死亡!由于当时苏联已经签署了著名的《禁止生物武器公约》,因此这条消息迅速引起了西方国家的注意。他们纷纷指责苏联军工厂生产生物武器,违反了公约的规定。不过,莫斯科当局迅速做出反驳,他们宣称是&b&“食用肉类遭到了炭疽的污染,进而导致有人得病死亡”&/b&,并且否认了任何关于违反联合国公约的指控。但事实上,苏联人已经成功掩盖了一起历史上最严重的生化武器泄露事故——&b&斯维尔德洛夫斯克炭疽泄露事件&/b&。&/p&&p&虽然苏联的炭疽泄漏与恐怖分子无关,但却揭露了“生化武器”禁而未止的事实,让人不寒而栗。&/p&&p&又因为苏联当局的隐瞒,这起恶性事件直到苏联解体后,真相才一点点浮出水面。&/p&&figure&&img src=&https://pic2.zhimg.com/50/v2-befb8fe40c9b97b_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&500& data-rawheight=&230& class=&origin_image zh-lightbox-thumb& width=&500& data-original=&https://pic2.zhimg.com/50/v2-befb8fe40c9b97b_r.jpg&&&/figure&&figure&&img src=&https://pic3.zhimg.com/50/v2-3d4d80ae86e57aaf7db84e0_b.jpg& data-size=&normal& data-rawwidth=&637& data-rawheight=&354& class=&origin_image zh-lightbox-thumb& width=&637& data-original=&https://pic3.zhimg.com/50/v2-3d4d80ae86e57aaf7db84e0_r.jpg&&&figcaption&1979年的叶卡捷琳堡,城内一片熙熙攘攘的热闹景象&/figcaption&&/figure&&p&1979年春天,莫斯科以东的一座城市 斯维尔德罗夫斯克 (Sverdlovsk,现属俄罗斯叫叶卡捷琳堡), 出现了一种 怪病 。&/p&&p&据当时苏联的报道,这次疾病的爆发至少有近一百名居民患病。&/p&&p&起初,病人的症状与流行性感冒极度相似,都是发热、干咳、胸痛等。&/p&&p&但几天后,他们的病症便直接升级为高热、呼吸困难、休克,以及大量内出血等多种严重并发症。&/p&&p&很快,68人死于非命。&/p&&figure&&img src=&https://pic4.zhimg.com/50/v2-958ebf02fe8c6ff9c15d_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&400& data-rawheight=&300& class=&content_image& width=&400&&&/figure&&p&虽然后来又出现了一些新的死亡病例,但确切的死亡人数已无法查证。&/p&&p&只是当时负责该城流行病爆发的贝比奇博士回忆道:&/p&&p&最严重时,有的人直接死在家中,或是行驶的电车上,一切都来得那么突然,根本来不及叫救护车。&/p&&p&当时的克格勃(苏联国家安全委员会)一致对外宣称,这是市民在私人屠宰场,购买并食用了被炭疽杆菌污染的坏肉,引起的 肠炭疽 感染 事故。&/p&&p&但事情又怎会如此简单?&/p&&blockquote&1979年4月的一天,前苏联工业重镇斯维尔德洛夫斯克市(Sverdlovsk,现名叶卡捷琳娜堡)的24号医院里,忽然送来了三位症状相似的病人,他们都表现为发高烧、头痛胸闷、喘不过气。&br&接手这几位病人的,是24号医院呼吸科的主治大夫玛格丽特·伊莉延科(Margarita Ilyenko)。她一开始以为是肺炎症状,但很快发现病人的病情恶化比他想象得要迅速得多。刚刚第二天凌晨,三位病人中就有两名已经死亡了,剩下的一名也奄奄一息:他的口鼻不断溢出渗血的黏液,因为呼吸极度困难已经陷入了昏迷。&br&就在第二天,城市中另一家20号医院里,也出现了同样的事情。&br&“我们这儿有几个病人很不对劲,高烧不退,一直剧烈咳嗽,还不断呕吐……”20号医院的呼吸科主治大夫雅科夫·克利普尼策尔(Yakov Klipnitzer)通过电话向伊莉延科焦虑地讨论病情。&br&“我们这里也是,一天之内大厅里就挤满了病人,病床上到处都是打着寒颤的人,很多病人的皮肤上都长出了黑色的水泡,看起来很恐怖。”伊莉延科回应道。&br&“这是怎么回事?难道是某种传染病吗……”&br&医生们的猜测并没有错,这些病人们的确感染了什么,只是他们从来没有接触过类似的病例,也不知道该如何医治。&br&短短一天之内,死亡人数就急剧上升到数十名,很快24号医院的停尸房里已经堆满了尸体,死神在这座中型城市里肆虐着……所有市民都开始惶恐起来,但却不知道这瘟疫是从何而起。&br&通过整理病人的档案,伊莉延科发现了病人们的某种共性:他们似乎都来自于城市32区,也就是奇卡洛夫斯基区的一家陶瓷厂。难道这家陶瓷厂内存在某种感染源吗?&br&此刻的陶瓷厂,已经暂时封闭。身穿严密防护服的疾控中心主任维克托·罗曼诺科(Viktor Romanenko)正在安排消毒人员不停地用氯气喷洒消毒。如果陶瓷厂正常工作时,可以透过厂房巨大的窗户,看见工厂内部挤满了上百名忙忙碌碌的工人。&br&很快,政府对外公布了结论,这是因为陶瓷厂工人们集体食用了某私人屠宰场贩卖的,被污染的肉类,才导致的瘟疫死亡事件。&br&“他们纯粹在胡扯,”在这家厂子上班的尼古拉·布米斯特罗夫(Nikolai Burmistrov)根本不相信这种解释,“我们很多人也吃了他们家的肉,为啥我们都没事?”&br&工人们的质疑是完全有道理的,特别是结合当时苏联的国际环境,再考虑到斯维尔德洛夫斯克市的城市定位,就不难猜测到,政府一定在隐瞒着某种可怕的真相……&/blockquote&&p&这样一看,斯维尔德罗夫斯克的炭疽感染事件,确实有蹊跷。&/p&&p&首先在历史上,就算是感染率最高的皮毛工人,都未曾出现过如此大规模的炭疽感染死亡事件。&/p&&figure&&img src=&https://pic4.zhimg.com/50/v2-1fad64dd60a796de46aa_b.jpg& data-size=&normal& data-rawwidth=&677& data-rawheight=&1024& class=&origin_image zh-lightbox-thumb& width=&677& data-original=&https://pic4.zhimg.com/50/v2-1fad64dd60a796de46aa_r.jpg&&&figcaption&斯维尔德罗斯克地区炭疽杆菌50公里直线感染区域。来源:1994年《科学杂志》&/figcaption&&/figure&&p&而且,仔细观察感染者在地图上的分布,病人竟都处于一条直线上。&/p&&p&引用后来负责调查此事件的哈佛生物学教授马修·梅塞尔逊(Matthew Meselson)的说法就是:“工人们吃肉并不会造成50公里内直线型区域感染的分布形状,只有风可以做到这一点”。他的妻子珍妮·吉列(Jeanne Guillemin)同样参与了此事件调查,并在1999年发布了一本专门介绍此事件的书:《炭疽:致命疫情的调查》(Anthrax: The Investigation of a Deadly Outbreak)。书中提到不仅仅是工人和市民,当地还有很多牲畜也同样感染了炭疽。&/p&&p&再结合当天的天气情况,当时风向正是朝着陶瓷厂刮过去,那么传播原因也就不言自明了。如此一来剩下的谜团只有一个:为什么炭疽会从19区的生化实验室里泄露出来?&/p&&p&答案来了:&/p&&p&冷战结束后逃到西方的苏联生物备战研究所副主任肯·阿里贝,他是一名哈萨克斯坦人,写于1999年的其个人回忆录名称正是取自著名电子游戏:《生化危机》&/p&&figure&&img src=&https://pic4.zhimg.com/50/v2-773ceeec717b3a_b.jpg& data-size=&normal& data-rawwidth=&330& data-rawheight=&492& class=&content_image& width=&330&&&figcaption&肯·阿里贝的回忆录《生化危机》&/figcaption&&/figure&&blockquote&“第19号营地是最繁忙的生化武器工厂,工人们三班倒地轮流工作,为苏联军火库制造一种干燥的粉末状炭疽武器。这是一项充满压力和危险的工作,发酵的炭疽菌必须从它们的液体基中分离出来,然后才能被磨成粉末,以便在弹头爆炸时形成气溶胶。尽管厂区里面的工人会定期接种疫苗,完全不用担心被炭疽感染,但是隔绝炭疽菌与外部世界接触的唯一一道防线,就是干燥机上面的排气管过滤网。在每次换班的时候,干燥机都会被关闭,进行例行检修维护。&br&在3月30日下午,技工在进行例行检修的时候发现一台干燥机的过滤网被堵住了,于是他们便将这个滤网拆下来清洗,并且准备让晚班的同事将滤网装回去。根据苏联军队的规定,当天下午的值班主管尼古拉中校,应该要在记录本上记下滤网已经被拆下的备注。但是这位中校看起来似乎非常急切地想要回家,或者只是他的确太累了,他忘记在记录本上记下关于滤网的信息!&br&当晚班的值班主管上工的时候,他没有在记录本上发现任何与滤网相关的信息,于是这位主管便让工人像往常那样启动机器,继续工作。就这样,武器级的炭疽病菌在干燥机的废气推动下,飞散到夜空之中。数小时后,操作干燥机的工人惊讶地发现,干燥机的滤网居然还放在地上!尽管他们迅速地把滤网装进了机器,但是大祸已经酿成了:一阵凉爽的晚风将致命的炭疽病菌带到了附近的陶瓷制品厂,感染了在这里上班的夜班工人,几乎所有工人都在一周之内因为病发死亡了!&br&在疫情爆发之前,斯维尔德洛夫斯克市政府当局完全被蒙在了鼓里。随后,军队和苏维埃高层迅速采取了掩盖行动。军队在疫区周边设立了隔离区,而苏联高层则对外宣称被污染的肉类是罪魁祸首。数百只流浪狗因此被枪杀,而黑市食品小贩则因‘传播受污染的食物’而被捕。KGB的特工人员摧毁了医院的记录和疫情的疫情报告,所有受害者的尸体被沐浴在化学战消毒剂中,以清除炭疽孢子留下的证据。&br&当地的领导人显然已经获悉了工厂里有危险物质泄露,他命令市政工人擦洗和修剪城市里的树木,喷洗道路和屋顶。结果,刚刚沉淀下来的炭疽孢子被工人们再次搅动,形成气溶胶继续扩散,导致城市中产生了多例皮肤炭疽病。”&/blockquote&&figure&&img src=&https://pic2.zhimg.com/50/v2-eaffb11719d_b.jpg& data-size=&normal& data-rawwidth=&896& data-rawheight=&618& class=&origin_image zh-lightbox-thumb& width=&896& data-original=&https://pic2.zhimg.com/50/v2-eaffb11719d_r.jpg&&&figcaption&19营区上空&/figcaption&&/figure&&figure&&img src=&https://pic2.zhimg.com/50/v2-390ab27cb5fa910e4d62_b.jpg& data-size=&normal& data-rawwidth=&600& data-rawheight=&387& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic2.zhimg.com/50/v2-390ab27cb5fa910e4d62_r.jpg&&&figcaption&炭疽粉末&/figcaption&&/figure&&figure&&img src=&https://pic2.zhimg.com/50/v2-f05eefa33cf87cf9e675_b.jpg& data-size=&normal& data-rawwidth=&1280& data-rawheight=&846& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&https://pic2.zhimg.com/50/v2-f05eefa33cf87cf9e675_r.jpg&&&figcaption&苏联时期哈萨克斯坦一处化武工厂的冷却装置&/figcaption&&/figure&&p&那时无人知晓有多少炭疽芽孢从19号营区飘出,但有专家估计 污染物不超过1千克 ,其中包含 不超过1克的炭疽芽孢 。&/p&&p&假设这些孢子能广泛扩散,就能致使 几十万居民 染病。&/p&&p&不过幸运的是,当时的炭疽孢子并没有落到市中心,因为风向刚好吹向了人烟稀少的地区。&/p&&p&&b&截至5月,至少有99名苏联民众在这场史上最严重的生化武器泄露事件中被炭疽感染,64人因此死亡。不过,但根据阿里贝书中的说法,总死亡人数可能接近105人。&/b&而附近30英里范围内的羊圈中,牧羊人则纷纷表示有羊上了炭疽病——因为羊比起人类更加容易感染这种传染病。由于这起事件的严重性,日后的生物学者将斯维尔德洛夫斯克炭疽泄露事件称为“生化版的切尔诺贝利事件”。&/p&&p&对炭疽来说,及早确诊与 使用抗生素 ,是病人能否存活的关键。但是,就算是致死率不高的皮肤性炭疽,如无适当治疗就极易演化为九死一生的吸入性肺炭疽。&/p&&p&若当时医院能早点知道病因,或许就能挽回一些病人的生命。&/p&&p&但是,苏联军方并没有向任何人透露这种怪病爆发的原因, 包括当地的卫生组织 。&/p&&figure&&img src=&https://pic2.zhimg.com/50/v2-87bce7bfd2636_b.jpg& data-size=&normal& data-rawwidth=&850& data-rawheight=&478& class=&origin_image zh-lightbox-thumb& width=&850& data-original=&https://pic2.zhimg.com/50/v2-87bce7bfd2636_r.jpg&&&figcaption&一位老人正在清理儿子的墓碑&/figcaption&&/figure&&p&然而,在所有人都还没搞清楚状况时,一个紧急事务小组就奔赴此地,没收了当时所有病人的医疗数据和尸检报告。&/p&&p&医院和平民区都被大量喷洒氯水,甚至连街道表面的泥土都被推土机挖走一层。&/p&&figure&&img src=&https://pic3.zhimg.com/50/v2-9ddea8700cbc09effbefc8f_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&400& data-rawheight=&400& class=&content_image& width=&400&&&/figure&&p&苏联当局只想极力把此事压下,因为事情败露也将意味着受到全世界的谴责。&/p&&p&毕竟,多个国家(包括苏联和美国),共同签署的那份 《禁止生物武器公约》 ,就摆在那儿。&/p&&p&但纸始终包不住火,1979年10月,西德法兰克福一家俄语报社便了解到情况,并率先报道了此事。&/p&&p&随后,德国的《图片报》更是剑指苏联生化武器泄漏,说明了这次灾难的源头。&/p&&figure&&img src=&https://pic1.zhimg.com/50/v2-c16aea104b1ddd769e506ba2_b.jpg& data-size=&normal& data-rawwidth=&400& data-rawheight=&323& class=&content_image& width=&400&&&figcaption&1972年签署《禁止生物武器公约》&/figcaption&&/figure&&p&虽说苏联对外公布的死亡人数,与在众多灾难相比并不算多。&/p&&p&但是这起事故揭露的事实,却能让人震惊之余,又不寒而栗。&/p&&p&如果苏联真的有生物武器项目,也就意味着《禁止生物武器公约》,形同一纸废书。&/p&&p&或许除苏联外,还有许多国家都未曾停止生物武器的研发。&/p&&figure&&img src=&https://pic2.zhimg.com/50/v2-f8b46d74e5f1aefd7a0a08_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&507& data-rawheight=&338& class=&origin_image zh-lightbox-thumb& width=&507& data-original=&https://pic2.zhimg.com/50/v2-f8b46d74e5f1aefd7a0a08_r.jpg&&&/figure&&p&虽然许多消息都直指背后真相,但是耍赖对一个大国来说并不是什么难事。&/p&&p&苏联坚称炭疽暴发是 自然爆发 , 拒不承认源于生物武器泄漏。&/p&&p&此外,苏联还反指责“美国的指责”会加剧两国紧张关系,并表示这是对1972年《禁止生物武器合约》合法性的质疑。&/p&&p&而在这之后的20年里,19营区的大门就紧闭着,从未有外国人获准许进去查证。&/p&&figure&&img src=&https://pic3.zhimg.com/50/v2-4abeac7f6750_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&650& data-rawheight=&365& class=&origin_image zh-lightbox-thumb& width=&650& data-original=&https://pic3.zhimg.com/50/v2-4abeac7f6750_r.jpg&&&/figure&&figure&&img src=&https://pic2.zhimg.com/50/v2-352fceda549f283a820bb_b.jpg& data-size=&normal& data-rawwidth=&410& data-rawheight=&257& class=&content_image& width=&410&&&figcaption&叶利钦&/figcaption&&/figure&&p&直至苏联解体之后,俄罗斯总统鲍里斯·叶利钦才在一次演讲上委婉地承认了这场泄露事件&/p&&p&直到苏联解体后的1993年,俄罗斯总统鲍里斯·叶利钦才在一次演讲中,以非常委婉的措辞承认斯维尔德洛夫斯克炭疽泄露事件。与此同时,前乌拉尔军区特别部门负责人安德烈·米罗纽科,也在2008年的一份杂志上承认了这次化武事故。这些描述间接支持了肯·阿里贝回忆录中的说法。不过,一些俄罗斯的官员至今依然坚持着“肉类中含有炭疽病菌”的说法,甚至宣称是美国间谍在肉食品中投毒,但是他们却无法提供令人信服的证据。&/p&&p&当时,叶利钦也准许来自哈佛的分子生物学小组,对此次炭疽泄漏事故进行实地调查。&/p&&p&除了还原事故发生经过,他们还从一位俄罗斯医生那里获得了一些 病人尸检样本 ,并带回美国深入研究。&/p&&figure&&img src=&https://pic1.zhimg.com/50/v2-ea7fc52fa2bf912de736d5d957eac250_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&500& data-rawheight=&376& class=&origin_image zh-lightbox-thumb& width=&500& data-original=&https://pic1.zhimg.com/50/v2-ea7fc52fa2bf912de736d5d957eac250_r.jpg&&&/figure&&p&到2015年,技术的进步也终于让美国科学家,重新构建出涉事炭疽的“真实身份”。&/p&&p&结果显示,这些炭疽杆菌竟属于著名的 “跨欧亚” 品系——与中国大陆境内广泛培养的疫苗株非常接近。&/p&&figure&&img src=&https://pic1.zhimg.com/50/v2-0ff717b4f1c941f4eafcfa3ce4947878_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&550& data-rawheight=&288& class=&origin_image zh-lightbox-thumb& width=&550& data-original=&https://pic1.zhimg.com/50/v2-0ff717b4f1c941f4eafcfa3ce4947878_r.jpg&&&/figure&&p&估计每一个中国人都不会忘记日本在中国横行的 “731部队” 。&/p&&p&在罪恶的731部队中,便有一条月产200公斤炭疽孢子粉末的生产线。&/p&&p&中国大量的平民都曾被当做小白鼠做实验,吸入大量炭疽粉末。&/p&&figure&&img src=&https://pic3.zhimg.com/50/v2-23c06fc747dc0b73d0b5c_b.jpg& data-size=&normal& data-rawwidth=&320& data-rawheight=&463& class=&content_image& width=&320&&&figcaption&中国炭疽菌受害幸存者&/figcaption&&/figure&&p&从1939年到1942年间,731部队生产的炭疽等病菌,就多达 数十吨 。&/p&&p&在日本战败后,731部队更是直接把不易携带的大部分炭疽等细菌散播在华中一带,只带了部分样品离开。&/p&&p&这也正是,1979年苏联生物武器泄漏的炭疽,竟与中国大陆广泛疫苗株相似的原因。&/p&&figure&&img src=&https://pic3.zhimg.com/50/v2-f011c1cba16d393c0f301dc65c6c3ab0_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&510& data-rawheight=&278& class=&origin_image zh-lightbox-thumb& width=&510& data-original=&https://pic3.zhimg.com/50/v2-f011c1cba16d393c0f301dc65c6c3ab0_r.jpg&&&/figure&&p&据专家推测,苏联的生物武器项目的建立,正是使用了大量日本731部队的文件和样品。&/p&&p&也就是说, 苏联的炭疽细菌武器,正是日本“731部队”的遗毒。&/p&&hr&&p&&b&二、炭疽&/b&&/p&&p&其实在历史上,炭疽曾被多国制成生物武器已是人尽皆知之事。&/p&&p&1876年,细菌学之父 罗伯特·科赫 就发现了能致牛羊、牧人死亡的炭疽杆菌。&/p&&p&虽然在自然界感染率不高,但炭疽还是凭着自身的多个优点受到 “生物武器” 的青睐。&/p&&figure&&img src=&https://pic2.zhimg.com/50/v2-fcb51ad7c74fb46aad3e2f6e_b.jpg& data-size=&normal& data-rawwidth=&612& data-rawheight=&332& class=&origin_image zh-lightbox-thumb& width=&612& data-original=&https://pic2.zhimg.com/50/v2-fcb51ad7c74fb46aad3e2f6e_r.jpg&&&figcaption&罗伯特·科赫&/figcaption&&/figure&&p&生物武器,常常被称为 “穷人的核武器” 。&/p&&p&曾经有微生物学家指出:&/p&&p&“如果恐怖分子想在全球肆虐,生物武器将会是首选。因为想要造成一平方公里内50%的死亡率,用常规武器需要2000美元,核武器需要800美元,化学武器则需600美元,而 生物武器 才是最便宜的, 只需 一美元足以 。”&/p&&figure&&img src=&https://pic3.zhimg.com/50/v2-2b88fc3ca3b57eb63f716f7b_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&478& data-rawheight=&286& class=&origin_image zh-lightbox-thumb& width=&478& data-original=&https://pic3.zhimg.com/50/v2-2b88fc3ca3b57eb63f716f7b_r.jpg&&&/figure&&p&上文里也说了,炭疽病(anthrax)是以炭疽杆菌的孢子作为传播媒介,它的得名来源于古希腊语中的“炭(anthrakos)”,这是因为当它接触皮肤后,会留下黑炭一般的焦黑色水泡,周围还会产生肿胀。&/p&&figure&&img src=&https://pic4.zhimg.com/50/v2-672829bcc74c1be56ae4c_b.jpg& data-size=&normal& data-rawwidth=&290& data-rawheight=&230& class=&content_image& width=&290&&&figcaption&皮肤炭疽&/figcaption&&/figure&&p&除了皮肤传染之外,炭疽病还可以通过呼吸道和消化系统传入,可以说是无孔不入了……&/p&&p&所有传播渠道中,呼吸道传播是最可怕的:一旦炭疽孢子通过呼吸道进入身体,它会首先潜入淋巴结,并在那里开始大量孵化繁殖……惊人数量的孢子最终会入侵血管,并引发大面积的组织损伤和内出血。&/p&&figure&&img src=&https://pic3.zhimg.com/50/v2-0cfd64cfdaa5_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&226& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic3.zhimg.com/50/v2-0cfd64cfdaa5_r.jpg&&&/figure&&p&如果没有及时治疗,呼吸道感染的炭疽病致死率高达85%(即便得到治疗致死率也达到45%……)&/p&&p&作为一种古老的,人畜共患的疾病,炭疽病早在古巴比伦时期就被发现了,在西方的《圣经》和我国的《黄帝内经》中均有所记载,是一种恐怖的瘟疫。1607年,中欧就有6万人死于炭疽病,俄国更是炭疽肆虐,仅1875年就有10万只牲畜死于炭疽病,因此炭疽病又被称为“西伯利亚病”。&/p&&figure&&img src=&https://pic4.zhimg.com/50/v2-02ec37eabcaf97a387510dc_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&375& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic4.zhimg.com/50/v2-02ec37eabcaf97a387510dc_r.jpg&&&/figure&&p&炭疽杆菌的孢子拥有相当强大的生存能力,很多普通的灭活方式都对它无效,无论用消毒剂浸泡,还是加温180摄氏度两分钟以内,都无法有效杀死炭疽孢子。甚至埋藏于地底的炭疽孢子,依然可以存活数百年之久。&/p&&p&比如中世纪苏格兰医院废墟上的考古挖掘中,就发现了炭疽孢子,以及几百年前用来杀死它们的石灰残骸,谁都没有想到,重见天日的这些孢子竟然复活了。&/p&&figure&&img src=&https://pic2.zhimg.com/50/v2-7d647b85ab6db5c3d22a3_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&407& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic2.zhimg.com/50/v2-7d647b85ab6db5c3d22a3_r.jpg&&&/figure&&p&而集成本低廉和致死率高这两个优点于一身的炭疽杆菌,也成了历史上经久不衰的 最强生物武器之一 。&/p&&p&又因为肺炭疽早期症状与正常流行性感冒极为相似。&/p&&p&所以经常出现误诊,使患者错过最佳治疗时间,一命呜呼。&/p&&figure&&img src=&https://pic1.zhimg.com/50/v2-2ca41ecfacec_b.jpg& data-size=&normal& data-rawwidth=&1280& data-rawheight=&619& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&https://pic1.zhimg.com/50/v2-2ca41ecfacec_r.jpg&&&figcaption&2001年炭疽邮件中的炭疽孢子&/figcaption&&/figure&&p&就算被感染的宿主尸体已经腐化,炭疽孢子还是能躲在土地里,等待 下一次“复活” 。&/p&&figure&&img src=&https://pic4.zhimg.com/50/v2-ba7fc65e468296fcc3f014_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&320& data-rawheight=&240& class=&content_image& width=&320&&&/figure&&p&在二战时期的英国,一场小小的实验,就足以让人类见识到炭疽武器的厉害。&/p&&p&那时,英国策划了名为 “素食行动” 的炭疽武器计划,设想通过向德国境内投放污染饲料,消灭牲畜以造成食物短缺。&/p&&p&当时的研究人员在报告中总结,如果对德国使用该武器,将令所有的城市陷入瘫痪,往后数十年将无法居住。&/p&&figure&&img src=&https://pic2.zhimg.com/50/v2-4e5f1d9c00f_b.jpg& data-size=&normal& data-rawwidth=&500& data-rawheight=&309& class=&origin_image zh-lightbox-thumb& width=&500& data-original=&https://pic2.zhimg.com/50/v2-4e5f1d9c00f_r.jpg&&&figcaption&格鲁伊纳岛上的警示牌&/figcaption&&/figure&&p&虽说素食行动最后未曾实施,但被用来作实验的 格林纳德岛, 却遭了殃。&/p&&p&1942年,英国人选择了苏格兰高地附近一座名叫格林纳德(Gruinard)的无人荒岛,在岛上用围栏围住了上百只绵羊,并通过飞机投弹和爆炸的方式,在岛上进行大规模炭疽武器实验。仅仅三天之后,绵羊就开始大规模死亡,岛上到处都留下它们浑身流血的尸体。&/p&&figure&&img src=&https://pic1.zhimg.com/50/v2-f0309bfa0716f6fad41b0fea9d162666_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&478& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic1.zhimg.com/50/v2-f0309bfa0716f6fad41b0fea9d162666_r.jpg&&&/figure&&p&虽然科研人员立刻对尸体进行的焚烧和掩埋处理,但在30多年之后的1979年,对岛上土壤的采样显示,每克土壤中依然存活着个炭疽孢子。最后,英国人只能用近300吨甲醛杀毒液洒满了岛上每一寸土地,才算解除了生化危机。只不过,这座岛至今仍然是荒芜的无人岛。&/p&&figure&&img src=&https://pic3.zhimg.com/50/v2-baaafac37bbbe978a61db_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&353& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic3.zhimg.com/50/v2-baaafac37bbbe978a61db_r.jpg&&&/figure&&hr&&p&&b&三、剧毒之岛&/b&&/p&&p&&br&&/p&&p&可惜斯维尔德洛夫斯克炭疽泄露事件之后,苏联人当年并没有立刻吸取教训。&/p&&p&1971年时,一群前苏联渔业科学家搭乘一艘名为雷夫·博格号(Lev Berg)的科考船,来到中亚咸海中一座名叫沃兹罗日杰尼耶(Vozrozhdeniya)的无人岛附近时考察当地水质时,因为小岛复杂的地形而迷了路。&/p&&p&博格号驶入了小岛深处,并在这里忽然遭遇了一团诡异的褐色烟雾。&/p&&figure&&img src=&https://pic3.zhimg.com/50/v2-a2c3ec01bffc8c_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&550& data-rawheight=&704& class=&origin_image zh-lightbox-thumb& width=&550& data-original=&https://pic3.zhimg.com/50/v2-a2c3ec01bffc8c_r.jpg&&&/figure&&p&当船只从烟雾中离开时,一名年轻的女科学家开始剧烈地咳嗽。&/p&&p&几天后,她开始出现发高烧38.9℃,头痛,肌肉酸痛的症状,并在就医后检查出她感染了天花,并立刻服用了抗生素和阿司匹林。虽然这位女科学家早前就接种过天花疫苗,但她的背部、面部和头皮上仍然长出了大片的皮疹。&/p&&p&因为治疗及时,这位女科学家幸运地逃过一死,但另外9名感染者就没那么好运气了,其中有三人死亡,包括她的弟弟。&/p&&p&一年之后,又有人发现小岛附近漂浮着两具当地渔民的尸体。在此之后,这座岛周围又出现了大量死亡的鱼类。根据附近渔民的说法,后来还有两个探险的户外爱好者上了岛之后,就再也没能回来……&/p&&figure&&img src=&https://pic3.zhimg.com/50/v2-12b848f279b78611fcccfe_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&338& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic3.zhimg.com/50/v2-12b848f279b78611fcccfe_r.jpg&&&/figure&&p&显然,岛上存在着什么致命的东西,让一起敢于接近它的生物,全都死于非命。&/p&&p&从外表上看,这座位于哈萨克斯坦和乌兹别克斯坦边境的小岛,并没有任何特别之处。&/p&&p&但是,通过中情局的机密航拍照片,可以看到这座岛上不但有码头,有渔民工作的木棚,还有一些类似于靶场和兵营的建筑。&/p&&figure&&img src=&https://pic3.zhimg.com/50/v2-97debdb79_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&420& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic3.zhimg.com/50/v2-97debdb79_r.jpg&&&/figure&&p&更诡异的是,岛上还有数量可观的动物围栏,和一些看似科研机构的建筑……&/p&&p&这不能不令人联想到,英国的那座死亡之岛——格林纳德。&/p&&p&事实上,这座与世隔绝且长期以来几乎无人知晓的小岛,很早就被苏联人看中了。1948年时,他们在这座岛上,建立了一个绝密的生物武器实验室。这做实验室隶属于一个被称为Aralsk-7的高度机密项目,整个项目的最终任务只有一个:规模化生产生物武器。&/p&&figure&&img src=&https://pic4.zhimg.com/50/v2-ee43ad412adcbf53f18d86d_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&374& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic4.zhimg.com/50/v2-ee43ad412adcbf53f18d86d_r.jpg&&&/figure&&p&因此,女科学家应该值得庆幸,1971年她只是遭遇了天花感染,更恐怖的东西,要到几年后才会降临岛上。&/p&&p&&b&1979年的斯维尔德洛夫斯克炭疽泄露事件爆发后,苏联人并没有舍得销毁那些他们苦心研究的宝贝。而是将大量的炭疽孢子混合在抑制其生长的漂白剂中,并成批地转移到了沃兹罗日杰尼耶岛上。&/b&&/p&&p&据估计,最终转移到岛上的炭疽孢子,竟然有100至200吨之多……&/p&&figure&&img src=&https://pic3.zhimg.com/50/v2-dd698c1e979f0c9acbd549_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&343& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic3.zhimg.com/50/v2-dd698c1e979f0c9acbd549_r.jpg&&&/figure&&p&可以想象一下,如果这些剧毒之物大量扩散出来,显然威胁性绝对远远超越切尔诺贝利事件。当年,这些炭疽孢子被放置在岛上一个叫做坎特贝克(Kantubek)的小镇附近。说是小镇,其实就是当年的实验基地和住宅区。&/p&&p&在这座连地图上都找不到的前苏联机密基地里,不仅存放有炭疽杆菌和天花病毒,还有伯纳特氏立克次体、土拉弗朗西斯杆菌、猪布鲁氏杆菌、普氏立克次体、鼠疫耶尔森氏杆菌、肉毒杆菌毒素和委内瑞拉马脑炎病毒等多种生物武器。&/p&&p&更不可思议的是,这里曾经还是一个集幼儿园、中小学、游乐场于一体的小社会(简直有种《辐射》背景的感觉)。&/p&&figure&&img src=&https://pic1.zhimg.com/50/v2-3eb5f603d2bffba8385728_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&395& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic1.zhimg.com/50/v2-3eb5f603d2bffba8385728_r.jpg&&&/figure&&p&更恐怖的是,1991年苏联解体后,这里的科研人员便开始大批撤离,他们留下了大量未经妥善处理的生化武器,并在此后的多年里数次泄露,最终让这座小岛变成了不折不扣的剧毒之岛。&/p&&p&2001年时,一批穿着严密的防护服的美国科学家,来到沃兹罗日杰尼耶岛上进行生化危害考察。&/p&&p&此时的岛上已经是一片荒芜,曾经的实验室已然只剩下断壁残垣,曾经用来饲养豚鼠、仓鼠和兔子的数百个笼子散落得到处都是。从实验室遗迹里的那些熔化的试管和培养皿就能看出,苏联人离开时显然放了一把大火,想把一切都焚毁。&/p&&figure&&img src=&https://pic2.zhimg.com/50/v2-fa79df5433972aeed38a2ec_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&389& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic2.zhimg.com/50/v2-fa79df5433972aeed38a2ec_r.jpg&&&/figure&&p&生化实验基地两公里开外的露天试验场,是用来测试生化炸弹的有效范围和扩散速度的。旷野里时不时有老鼠和昆虫出没,小队成员全都小心翼翼地躲开它们。理论上而言,生命力强悍的它们,如今也是病毒和细菌的绝佳载体。&/p&&p&如今虽然除了小队成员岛上空无一人,但谁都不敢掉以轻心,毕竟这里四下潜伏着比人类更加可怕的生命体。&/p&&figure&&img src=&https://pic2.zhimg.com/50/v2-fe8bd020_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&600& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic2.zhimg.com/50/v2-fe8bd020_r.jpg&&&/figure&&p&通过一番调查,这帮冒险家吃惊地发现,因为岛上的植被稀疏,加上沙漠气候的炎热天气(夏季温度可达60℃),大部分病毒和微生物都被杀死了。但是,依然还有一个唯一的例外,你们都想象得到的:炭疽。&/p&&p&由于某些区域有炭疽的存在,仅仅十五分钟后,队员的防毒面罩过滤器就开始报警:呼吸器的滤芯已经饱和,不能再使用了……&/p&&figure&&img src=&https://pic4.zhimg.com/50/v2-22e23c3b2c66f04faaca1a97ed48ac6b_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&375& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic4.zhimg.com/50/v2-22e23c3b2c66f04faaca1a97ed48ac6b_r.jpg&&&/figure&&p&考察队员决定当天就离开沃兹罗日杰尼耶岛,在临行前,一名队员在笔记本上写下了这样的笔记:岛上的污染状况比想象中好很多,如果能够进行一次彻底的消毒喷洒,也许可以消除危险。希望这座“重生之岛(岛名的意思就是rebirth)”上,炭疽永不重生。&/p&&figure&&img src=&https://pic2.zhimg.com/50/v2-b7bd1a88f4d5d395ddb5e34f051b74b5_b.jpg& data-size=&normal& data-rawwidth=&876& data-rawheight=&685& class=&origin_image zh-lightbox-thumb& width=&876& data-original=&https://pic2.zhimg.com/50/v2-b7bd1a88f4d5d395ddb5e34f051b74b5_r.jpg&&&figcaption&今天的沃兹罗日杰尼耶(Vozrozhdeniya)岛上的基地遗址&/figcaption&&/figure&&p&全文完。&/p&
没人说说咸海中间那个岛吗?生化危机BIOHAZARD这个单词鼎鼎大名啊!挖个坑吧半个月后,我终于来填坑了!本文内容收集整理自网络,其中大部分内容来自原作者 的 本文有大量的文字和图片内容,请谨慎阅读。 一、斯维尔德罗夫斯克 在《生化危机3…
&p&TL;DR:&/p&&p&System.Int32类型重写了&code&object.Equals(object)&/code&方法,当对象是int时,它能与参数进行数值比较,所以在o1.Equals(o2)时,使用了重写的&code&int.Equals(object)&/code&,方法,进行了数值比较,返回True。&/p&&p&根据重载方法的静态分派原则,o1 == o2由于都是object引用类型引用,所以调用了==操作符的&code&bool object.operator==(object, object)&/code&版本,这个重载版本调用了&code&object.ReferenceEquals(object,object)&/code&方法,直接比较两个对象的地址。由于o1和o2的地址不同,所以返回False。&/p&&hr&&p&长一点的答案:&/p&&p&&br&&/p&&p&这个问题涉及到值类型的&b&装箱(boxing)&/b&以及&b&多态的静态和动态分派(static/dynamic dispatch)。&/b&&/p&&p&&br&&/p&&p&先介绍一个方法:&/p&&p&&code&object.ReferenceEquals(object,object)&/code& &/p&&p&比较两个对象的地址,若相同返回True,反之返回False。&/p&&p&&br&&/p&&p&并强调重载(overload)和重写(override)的区别:&/p&&p&&b&重载&/b&,为同一个方法名有多种不同签名的实现,它们&b&实际上是不同的方法,只是名字恰好一样&/b&。对于&code&==&/code&操作符,有&b&不同的重载版本&/b&,例如&code&bool operator==(int, int)&/code&以及&code&bool operator==(object, object)&/code&即为两个不同的版本。 在实际调用时,会根据&b&引用&/b&(不是实际对象)的类型来调用不同的版本。&/p&&p&&b&重写&/b&,为类继承里,子类重新实现了父类的方法。对于&code&object.Equals(object)&/code&方法,object类有一个默认实现;而对任何一个派生于object的类,都可以重写Equals方法,使这个方法在这个对应类的实例上调用时,使用不同的版本。比如Int32类型重写了这个方法(&code&int.Equals(object)&/code&)。在实际调用时,会根据&b&实际对象&/b&(而不是引用)的类型来选择方法。&/p&&p&&br&&/p&&p&int(Int32)是一个值类型,产生值类型对象的过程是:&/p&&ol&&li&在&b&栈&/b&上产生对象&/li&&li&在栈上返回对这个值类型对象的引用,为了方便简称&b&值类型引用&/b&&/li&&/ol&&p&值类型引用有如下特点:&/p&&ol&&li&默认没有&code&==&/code&操作符实现,可以自己重载;&/li&&li&Equals方法的默认实现为,当且仅当所有成员的Equals方法都返回True时,返回True;反之返回False。&/li&&/ol&&p&具体请看下面的代码。&/p&&div class=&highlight&&&pre&&code class=&language-text&&struct A
public A(int a) { this.a = }
A a1 = new A(1);
A a2 = new A(1);
// a1 == a2; 值类型引用默认不能使用==操作符,编译不通过。
a1.Equals(a2);
// True。int成员a相等(实际上是所有成员变量Equals方法返回True)
object.ReferenceEquals(a1, a2); // False,地址不同。
&/code&&/pre&&/div&&p&所以,如果题主的代码如下,那么&/p&&div class=&highlight&&&pre&&code class=&language-text&&int o1 = 1; // 值类型引用
int o2 = 1;
o1 == o2; // True。使用版本:int.operator==(int, int);
o1.Equals(o2); //True。使用版本:int.Equals(int);
object.ReferenceEquals(o1, o2); // False。地址不同。
&/code&&/pre&&/div&&p&&br&&/p&&p&但是,题主的前两句是&/p&&div class=&highlight&&&pre&&code class=&language-text&&object o1 = 1;
object o2 = 1;
&/code&&/pre&&/div&&p&那么这里就发生了值类型的&b&装箱&/b&操作。装箱的过程可以理解为&/p&&ol&&li&在&b&堆&/b&上产生对象;&/li&&li&在&b&栈&/b&上产生了&b&指向这个引用类型(object)对象的引用&/b&,简称引用类型引用。&/li&&/ol&&p&所以,这里o1和o2不再是&b&值类型引用&/b&,而是&b&引用类型引用&/b&。而引用类型引用的特点有:&/p&&ol&&li&有默认&code&==&/code&操作符重载版本(&code&bool object.operator ==(object, object)&/code&)&/li&&li&有默认Equals实现(在object类中,是虚方法,可重写)&/li&&li&&b&默认&code&==&/code&操作符和Equals方法的实现都是调用ReferenceEquals(重要!)&/b&&/li&&/ol&&p&&br&&/p&&p&所以,对一个普通的&b&没有重写Equals方法&/b&的两个引用类型引用,会有以下的结果&/p&&div class=&highlight&&&pre&&code class=&language-text&&class B
public B(int b) { this.b = }
B b1 = new B(2);
B b2 = new B(2);
object.ReferenceEquals(b1, b2); // False
// 直接比较引用的地址,地址不同。
b1 == b2; // False
// 使用版本bool object.operator==(object, object),
// 默认实现为调用ReferenceEquals方法,等价于上一行
null == b2; // False
// 使用版本bool object.operator==(object, object),
// 默认实现为调用ReferenceEquals方法,等价于第一行
b1.Equals(b2);
// 使用版本object.Equals(object),
// 默认实现为调用ReferenceEquals方法,等价于第一行。
&/code&&/pre&&/div&&p&&b&然而,我们知道int类是重写了Equals方法的!&/b&&/p&&p&所以,回到题目,如果我们将题目中的o1和o2拿来跑这些代码的话,其结果是:&/p&&div class=&highlight&&&pre&&code class=&language-text&&object o1 = 1; //引用类型引用
object o2 = 1;
object.ReferenceEquals(o1, o2); // False
o1 == o2; // False
// 静态分派,根据o1和o2的引用的类型,选择了bool operator==(object, object)版本
null == o2; // False
o1.Equals(o2);
// 动态分派,o1的实际类型是int,使用了int.Equals(object)方法,进行了数值比较。
&/code&&/pre&&/div&
TL;DR:System.Int32类型重写了object.Equals(object)方法,当对象是int时,它能与参数进行数值比较,所以在o1.Equals(o2)时,使用了重写的int.Equals(object),方法,进行了数值比较,返回True。根据重载方法的静态分派原则,o1 == o2由于都是object引用类…
&figure&&img src=&https://pic4.zhimg.com/v2-0b35a3df0b2ef_b.jpg& data-rawwidth=&728& data-rawheight=&397& class=&origin_image zh-lightbox-thumb& width=&728& data-original=&https://pic4.zhimg.com/v2-0b35a3df0b2ef_r.jpg&&&/figure&&h2&&b&&i&前言&/i&&/b&&/h2&&p&我们都知道,javascript从诞生之日起就是一门单线程的非阻塞的脚本语言。这是由其最初的用途来决定的:与浏览器交互。&/p&&p&单线程意味着,javascript代码在执行的任何时候,都只有一个主线程来处理所有的任务。&/p&&p&而非阻塞则是当代码需要进行一项异步任务(无法立刻返回结果,需要花一定时间才能返回的任务,如I/O事件)的时候,主线程会挂起(pending)这个任务,然后在异步任务返回结果的时候再根据一定规则去执行相应的回调。&/p&&p&单线程是必要的,也是javascript这门语言的基石,原因之一在其最初也是最主要的执行环境——浏览器中,我们需要进行各种各样的dom操作。试想一下 如果javascript是多线程的,那么当两个线程同时对dom进行一项操作,例如一个向其添加事件,而另一个删除了这个dom,此时该如何处理呢?因此,为了保证不会 发生类似于这个例子中的情景,javascript选择只用一个主线程来执行代码,这样就保证了程序执行的一致性。&/p&&p&当然,现如今人们也意识到,单线程在保证了执行顺序的同时也限制了javascript的效率,因此开发出了web worker技术。这项技术号称让javascript成为一门多线程语言。&/p&&p&然而,使用web worker技术开的多线程有着诸多限制,例如:所有新线程都受主线程的完全控制,不能独立执行。这意味着这些“线程” 实际上应属于主线程的子线程。另外,这些子线程并没有执行I/O操作的权限,只能为主线程分担一些诸如计算等任务。所以严格来讲这些线程并没有完整的功能,也因此这项技术并非改变了javascript语言的单线程本质。&/p&&p&可以预见,未来的javascript也会一直是一门单线程的语言。&/p&&p&话说回来,前面提到javascript的另一个特点是“非阻塞”,那么javascript引擎到底是如何实现的这一点呢?答案就是今天这篇文章的主角——event loop(事件循环)。&/p&&p&&i&注:虽然nodejs中的也存在与传统浏览器环境下的相似的事件循环。然而两者间却有着诸多不同,故把两者分开,单独解释。&/i&&/p&&h2&&b&&i&正文&/i&&/b&&/h2&&h2&&b&浏览器环境下js引擎的事件循环机制&/b&&/h2&&h2&&b&1.执行栈与事件队列&/b&&/h2&&p&当javascript代码执行的时候会将不同的变量存于内存中的不同位置:堆(heap)和栈(stack)中来加以区分。其中,堆里存放着一些对象。而栈中则存放着一些基础类型变量以及对象的指针。 但是我们这里说的执行栈和上面这个栈的意义却有些不同。&/p&&p&我们知道,当我们调用一个方法的时候,js会生成一个与这个方法对应的执行环境(context),又叫执行上下文。这个执行环境中存在着这个方法的私有作用域,上层作用域的指向,方法的参数,这个作用域中定义的变量以及这个作用域的this对象。 而当一系列方法被依次调用的时候,因为js是单线程的,同一时间只能执行一个方法,于是这些方法被排队在一个单独的地方。这个地方被称为执行栈。&/p&&p&当一个脚本第一次执行的时候,js引擎会解析这段代码,并将其中的同步代码按照执行顺序加入执行栈中,然后从头开始执行。如果当前执行的是一个方法,那么js会向执行栈中添加这个方法的执行环境,然后进入这个执行环境继续执行其中的代码。当这个执行环境中的代码 执行完毕并返回结果后,js会退出这个执行环境并把这个执行环境销毁,回到上一个方法的执行环境。。这个过程反复进行,直到执行栈中的代码全部执行完毕。&/p&&p&下面这个图片非常直观的展示了这个过程,其中的global就是初次运行脚本时向执行栈中加入的代码:&/p&&p&&br&&/p&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-2f761eb83b50f53d741e6aa1f15a9db1_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&390& data-rawheight=&259& data-thumbnail=&https://pic1.zhimg.com/v2-2f761eb83b50f53d741e6aa1f15a9db1_b.jpg& class=&content_image& width=&390&&&/figure&&p&&br&&/p&&p&&br&&/p&&p&从图片可知,一个方法执行会向执行栈中加入这个方法的执行环境,在这个执行环境中还可以调用其他方法,甚至是自己,其结果不过是在执行栈中再添加一个执行环境。这个过程可以是无限进行下去的,除非发生了栈溢出,即超过了所能使用内存的最大值。&/p&&p&以上的过程说的都是同步代码的执行。那么当一个异步代码(如发送ajax请求数据)执行后会如何呢?前文提过,js的另一大特点是非阻塞,实现这一点的关键在于下面要说的这项机制——事件队列(Task Queue)。&/p&&p&js引擎遇到一个异步事件后并不会一直等待其返回结果,而是会将这个事件挂起,继续执行执行栈中的其他任务。当一个异步事件返回结果后,js会将这个事件加入与当前执行栈不同的另一个队列,我们称之为事件队列。被放入事件队列不会立刻执行其回调,而是等待当前执行栈中的所有任务都执行完毕, 主线程处于闲置状态时,主线程会去查找事件队列是否有任务。如果有,那么主线程会从中取出排在第一位的事件,并把这个事件对应的回调放入执行栈中,然后执行其中的同步代码...,如此反复,这样就形成了一个无限的循环。这就是这个过程被称为“事件循环(Event Loop)”的原因。&/p&&p&这里还有一张图来展示这个过程:&/p&&p&&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-da078fa3eadf3db4bff84b_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&601& data-rawheight=&527& class=&origin_image zh-lightbox-thumb& width=&601& data-original=&https://pic2.zhimg.com/v2-da078fa3eadf3db4bff84b_r.jpg&&&/figure&&p&&br&&/p&&p&图中的stack表示我们所说的执行栈,web apis则是代表一些异步事件,而callback queue即事件队列。&/p&&h2&&b&2.macro task与micro task&/b&&/h2&&p&以上的事件循环过程是一个宏观的表述,实际上因为异步任务之间并不相同,因此他们的执行优先级也有区别。不同的异步任务被分为两类:微任务(micro task)和宏任务(macro task)。&/p&&p&以下事件属于宏任务:&/p&&ul&&li&&code&setInterval()&/code&&/li&&li&&code&setTimeout()&/code&&/li&&/ul&&p&以下事件属于微任务&/p&&ul&&li&&code&new Promise()&/code&&/li&&li&&code&new MutaionObserver()&/code&&/li&&/ul&&p&前面我们介绍过,在一个事件循环中,异步事件返回结果后会被放到一个任务队列中。然而,根据这个异步事件的类型,这个事件实际上会被对应的宏任务队列或者微任务队列中去。并且在当前执行栈为空的时候,主线程会 查看微任务队列是否有事件存在。如果不存在,那么再去宏任务队列中取出一个事件并把对应的回到加入当前执行栈;如果存在,则会依次执行队列中事件对应的回调,直到微任务队列为空,然后去宏任务队列中取出最前面的一个事件,把对应的回调加入当前执行栈...如此反复,进入循环。&/p&&p&我们只需记住&b&当当前执行栈执行完毕时会立刻先处理所有微任务队列中的事件,然后再去宏任务队列中取出一个事件。同一次事件循环中,微任务永远在宏任务之前执行&/b&。&/p&&p&这样就能解释下面这段代码的结果:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&setTimeout(function () {
console.log(1);
new Promise(function(resolve,reject){
console.log(2)
resolve(3)
}).then(function(val){
console.log(val);
&/code&&/pre&&/div&&p&结果为:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&2
&/code&&/pre&&/div&&h2&&b&node环境下的事件循环机制&/b&&/h2&&h2&&b&1.与浏览器环境有何不同?&/b&&/h2&&p&在node中,事件循环表现出的状态与浏览器中大致相同。不同的是node中有一套自己的模型。node中事件循环的实现是依靠的libuv引擎。我们知道node选择chrome v8引擎作为js解释器,v8引擎将js代码分析后去调用对应的node api,而这些api最后则由libuv引擎驱动,执行对应的任务,并把不同的事件放在不同的队列中等待主线程执行。 因此实际上node中的事件循环存在于libuv引擎中。&/p&&h2&&b&2.事件循环模型&/b&&/h2&&p&下面是一个libuv引擎中的事件循环的模型:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span& ┌───────────────────────┐
└──────────┬────────────┘
┌──────────┴────────────┐
I/O callbacks
└──────────┬────────────┘
┌──────────┴────────────┐
idle, prepare
└──────────┬────────────┘
┌───────────────┐
┌──────────┴────────────┐
│&──connections───
└──────────┬────────────┘
data, etc.
┌──────────┴────────────┐
└───────────────┘
└──────────┬────────────┘
┌──────────┴────────────┐
close callbacks
└───────────────────────┘
&/code&&/pre&&/div&&p&&i&注:模型中的每一个方块代表事件循环的一个阶段&/i&&/p&&p&这个模型是node官网上的一篇文章中给出的,我下面的解释也都来源于这篇文章。我会在文末把文章地址贴出来,有兴趣的朋友可以亲自与看看原文。&/p&&h2&&b&3.事件循环各阶段详解&/b&&/h2&&p&从上面这个模型中,我们可以大致分析出node中的事件循环的顺序:&/p&&p&外部输入数据--&轮询阶段(poll)--&检查阶段(check)--&关闭事件回调阶段(close callback)--&定时器检测阶段(timer)--&I/O事件回调阶段(I/O callbacks)--&闲置阶段(idle, prepare)--&轮询阶段...&/p&&p&以上各阶段的名称是根据我个人理解的翻译,为了避免错误和歧义,下面解释的时候会用英文来表示这些阶段。&/p&&p&这些阶段大致的功能如下:&/p&&ul&&li&timers: 这个阶段执行定时器队列中的回调如 &code&setTimeout()&/code& 和 &code&setInterval()&/code&。&/li&&li&I/O callbacks: 这个阶段执行几乎所有的回调。但是不包括close事件,定时器和&code&setImmediate()&/code&的回调。&/li&&li&idle, prepare: 这个阶段仅在内部使用,可以不必理会。&/li&&li&poll: 等待新的I/O事件,node在一些特殊情况下会阻塞在这里。&/li&&li&check: &code&setImmediate()&/code&的回调会在这个阶段执行。&/li&&li&close callbacks: 例如&code&socket.on('close', ...)&/code&这种close事件的回调。&/li&&/ul&&p&下面我们来按照代码第一次进入libuv引擎后的顺序来详细解说这些阶段:&/p&&h2&&b&poll阶段&/b&&/h2&&p&当个v8引擎将js代码解析后传入libuv引擎后,循环首先进入poll阶段。poll阶段的执行逻辑如下: 先查看poll queue中是否有事件,有任务就按先进先出的顺序依次执行回调。 当queue为空时,会检查是否有setImmediate()的callback,如果有就进入check阶段执行这些callback。但同时也会检查是否有到期的timer,如果有,就把这些到期的timer的callback按照调用顺序放到timer queue中,之后循环会进入timer阶段执行queue中的 callback。 这两者的顺序是不固定的,收到代码运行的环境的影响。如果两者的queue都是空的,那么loop会在poll阶段停留,直到有一个i/o事件返回,循环会进入i/o callback阶段并立即执行这个事件的callback。&/p&&p&值得注意的是,poll阶段在执行poll queue中的回调时实际上不会无限的执行下去。有两种情况poll阶段会终止执行poll queue中的下一个回调:1.所有回调执行完毕。2.执行数超过了node的限制。&/p&&h2&&b&check阶段&/b&&/h2&&p&check阶段专门用来执行&code&setImmediate()&/code&方法的回调,当poll阶段进入空闲状态,并且setImmediate queue中有callback时,事件循环进入这个阶段。&/p&&h2&&b&close阶段&/b&&/h2&&p&当一个socket连接或者一个handle被突然关闭时(例如调用了&code&socket.destroy()&/code&方法),close事件会被发送到这个阶段执行回调。否则事件会用&code&process.nextTick()&/code&方法发送出去。&/p&&h2&&b&timer阶段&/b&&/h2&&p&这个阶段以先进先出的方式执行所有到期的timer加入timer队列里的callback,一个timer callback指得是一个通过setTimeout或者setInterval函数设置的回调函数。&/p&&h2&&b&I/O callback阶段&/b&&/h2&&p&如上文所言,这个阶段主要执行大部分I/O事件的回调,包括一些为操作系统执行的回调。例如一个TCP连接生错误时,系统需要执行回调来获得这个错误的报告。&/p&&h2&&b&4.process.nextTick,setTimeout与setImmediate的区别与使用场景&/b&&/h2&&p&在node中有三个常用的用来推迟任务执行的方法:process.nextTick,setTimeout(setInterval与之相同)与setImmediate&/p&&p&这三者间存在着一些非常不同的区别:&/p&&h2&&b&process.nextTick()&/b&&/h2&&p&尽管没有提及,但是实际上node中存在着一个特殊的队列,即nextTick queue。这个队列中的回调执行虽然没有被表示为一个阶段,当时这些事件却会在每一个阶段执行完毕准备进入下一个阶段时优先执行。当事件循环准备进入下一个阶段之前,会先检查nextTick queue中是否有任务,如果有,那么会先清空这个队列。与执行poll queue中的任务不同的是,这个操作在队列清空前是不会停止的。这也就意味着,错误的使用&code&process.nextTick()&/code&方法会导致node进入一个死循环。。直到内存泄漏。&/p&&p&那么合适使用这个方法比较合适呢?下面有一个例子:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&const server = net.createServer(() =& {}).listen(8080);
server.on('listening', () =& {});
&/code&&/pre&&/div&&p&这个例子中当,当listen方法被调用时,除非端口被占用,否则会立刻绑定在对应的端口上。这意味着此时这个端口可以立刻触发listening事件并执行其回调。然而,这时候&code&on('listening)&/code&还没有将callback设置好,自然没有callback可以执行。为了避免出现这种情况,node会在listen事件中使用&code&process.nextTick()&/code&方法,确保事件在回调函数绑定后被触发。&/p&&h2&&b&setTimeout()和setImmediate()&/b&&/h2&&p&在三个方法中,这两个方法最容易被弄混。实际上,某些情况下这两个方法的表现也非常相似。然而实际上,这两个方法的意义却大为不同。&/p&&p&&code&setTimeout()&/code&方法是定义一个回调,并且希望这个回调在我们所指定的时间间隔后第一时间去执行。注意这个“第一时间执行”,这意味着,受到操作系统和当前执行任务的诸多影响,该回调并不会在我们预期的时间间隔后精准的执行。执行的时间存在一定的延迟和误差,这是不可避免的。node会在可以执行timer回调的第一时间去执行你所设定的任务。&/p&&p&&code&setImmediate()&/code&方法从意义上将是立刻执行的意思,但是实际上它却是在一个固定的阶段才会执行回调,即poll阶段之后。有趣的是,这个名字的意义和之前提到过的&code&process.nextTick()&/code&方法才是最匹配的。node的开发者们也清楚这两个方法的命名上存在一定的混淆,他们表示不会把这两个方法的名字调换过来---因为有大量的node程序使用着这两个方法,调换命名所带来的好处与它的影响相比不值一提。&/p&&p&&code&setTimeout()&/code&和不设置时间间隔的&code&setImmediate()&/code&表现上及其相似。猜猜下面这段代码的结果是什么?&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&setTimeout(() =& {
console.log('timeout');
setImmediate(() =& {
console.log('immediate');
&/code&&/pre&&/div&&p&实际上,答案是不一定。没错,就连node的开发者都无法准确的判断这两者的顺序谁前谁后。这取决于这段代码的运行环境。运行环境中的各种复杂的情况会导致在同步队列里两个方法的顺序随机决定。但是,在一种情况下可以准确判断两个方法回调的执行顺序,那就是在一个I/O事件的回调中。下面这段代码的顺序永远是固定的:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&const fs = require('fs');
fs.readFile(__filename, () =& {
setTimeout(() =& {
console.log('timeout');
setImmediate(() =& {
console.log('immediate');
&/code&&/pre&&/div&&p&答案永远是:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&immediate
&/code&&/pre&&/div&&p&因为在I/O事件的回调中,setImmediate方法的回调永远在timer的回调前执行。&/p&&h2&&b&&i&尾声&/i&&/b&&/h2&&p&javascrit的事件循环是这门语言中非常重要且基础的概念。清楚的了解了事件循环的执行顺序和每一个阶段的特点,可以使我们对一段异步代码的执行顺序有一个清晰的认识,从而减少代码运行的不确定性。合理的使用各种延迟事件的方法,有助于代码更好的按照其优先级去执行。这篇文章期望用最易理解的方式和语言准确描述事件循环这个复杂过程,但由于作者自己水平有限,文章中难免出现疏漏。如果您发现了文章中的一些问题,欢迎在留言中提出,我会尽量回复这些评论,把错误更正。&/p&&h2&&b&&i&引用&/i&&/b&&/h2&&a href=&https://link.zhihu.com/?target=https%3A//www.cnblogs.com/mqliutie/p/4422247.html& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic4.zhimg.com/v2-dd640e2b46f4fbf_180x120.jpg& data-image-width=&554& data-image-height=&447& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&JavaScript中执行环境和栈 - 陪伴是最长情的告白 - 博客园&/a&&a href=&https://link.zhihu.com/?target=http%3A//js.walfud.com/macrotask-microtask/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic3.zhimg.com/v2-415f989adae7cc0f3a8b36c_120x160.jpg& data-image-width=&1079& data-image-height=&1793& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Macrotask 与 Microtask 核心概念&/a&&a href=&https://link.zhihu.com/?target=https%3A//nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/& data-draft-node=&block& data-draft-type=&link-card& data-image=&https://pic1.zhimg.com/v2-bff8f35baaea8_ipico.jpg& data-image-width=&224& data-image-height=&256& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&The Node.js Event Loop, Timers, and process.nextTick() | Node.js&/a&&p&&/p&
前言我们都知道,javascript从诞生之日起就是一门单线程的非阻塞的脚本语言。这是由其最初的用途来决定的:与浏览器交互。单线程意味着,javascript代码在执行的任何时候,都只有一个主线程来处理所有的任务。而非阻塞则是当代码需要进行一项异步任务(无法…
&p&在中国的游戏环境下,反挂已经成为了游戏开发的重中之重,甚至能决定一款游戏的生死,吃鸡就是一个典型的案例。&br&&br&目前参与了了一款动作射击的MOBA类游戏的开发,同步方案上选择了帧同步技术(LockStep而非snapshots以下同)。那么就有很多人担心起来,客户端会跑全部逻辑帧同步该如何反外挂,和状态同步有什么区别呢?&br&&br&首先我们来分析一下手游的风险和外挂的分类,这里推荐腾讯游戏安全中心的文章,有着非常详细深入的介绍。&br&手游的风险:&br& o 静态修改文件:将游戏解包修改资源 ,配置,代码等之后再重新打包&br&
○ 修改资源,例如替换游戏的贴图做广告,修改玩家碰撞资源 或删除部分关键资源使玩家可以作弊等&br&
○ 修改代码,直接修改游戏代码,实现无敌,免CD,无限伤害等等&br&
○ 修改配置,修改策划配表等&br& o 动态篡改逻辑:通过注入和钩子的方式,在游戏运行时修改游戏代码,修改游戏内存等&br&
○ 修改代码,运行时注入进程直接修改游戏代码或者钩住关键逻辑函数修改逻辑,实现无敌,免CD,无限伤害等等&br&
○ 修改内存,例如烧饼,葫芦侠等修改器,在游戏运行时修改堆栈和全局变量等&br& o 游戏协议&br&
○ 篡改游戏协议,直接修改协议的内容,修改结算结果,修改伤害数值,修改血量等等&br&
○ 重复游戏协议,例如多次重复伤害协议&br& o 其他,按键精灵。脚本宏,盗号,恶意发言,打金工作室等,这些和同步技术无关,暂不做详细讨论&br&&br&外挂的分类 :&br&&/p&&figure&&img data-rawheight=&332& src=&https://pic4.zhimg.com/v2-4bdc7289acd48b9f18e404_b.jpg& data-size=&normal& data-rawwidth=&642& class=&origin_image zh-lightbox-thumb& width=&642& data-original=&https://pic4.zhimg.com/v2-4bdc7289acd48b9f18e404_r.jpg&&&/figure&&p&&a href=&https://link.zhihu.com/?target=http%3A//gslab.qq.com/portal.php%3Fmod%3Dview%26aid%3D94& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&摘自腾讯游戏安全实验室&/a&&br&&br&从上文可以看出外挂的主要方式还是修改客户端的资源,代码,和内存。因此反外挂的手段也不外乎以下几种:&br& o 服务器计算关键逻辑。例如一些MMO战斗逻辑泡在服务端&br& o 服务器验证客户端逻辑。包括通过完整战斗逻辑验证和数值范围验证,例如早期的酷跑(可能误杀牛逼的玩家)&br& o 包体加密加签名加验证,防止破解包体。例如一些第三方加固,Unity的MonoDll加密,代码混淆等&br& o 加密本地保存的一些文件。例如对加密PlayerPrefs文件&br& o 加密和扰动运行时内存中关键数据(例如血量数据等)。例如崩3等&br& o 防注入检测(杀死注入进程或者发现注入之后杀死自己)&br& o 虚拟机加密&br& o 加速检测,防止修改本地时间的变速齿轮&br& o 穿墙检测,客户端对关键碰撞做校验&br& o 集成守护进程以及守护进程的自我加密更新&br& o 鼠标宏,按键精灵等进程检测,防止玩家使用这些工具&br& o 增加举报系统查证封号&br& o 通过暴力机关严厉打击外挂制作者(个人感觉非常有效)&br& o 其他&br&&br&但很遗憾,因为理论上再牛逼的客户端也是可以破解的,所以客户端的东西都是不可信任的。就像市面上也有很多第三方的加固工具,反作弊插件等,但不管用什么eye,什么火眼精睛,该作弊的还是作弊。因此反外挂的核心还是在于是否服务器是否计算了关键逻辑,就像Unreal老大说的The Server Is The Man。而和同步技术和客户端是否跑完整逻辑关系不大(严格说是有一点关系)。不管是状态同步还是帧同步,只要做到了服务器有完整逻辑并验证,绝大部分外挂都可以防掉(例如锁血挂,穿墙挂,加速挂等)。&br&&br&对于状态同步来说关键逻辑在服务器的比重越高反外挂就越完美。最极端的例子就是就是云游戏,服务器计算所有逻辑和画面,客户端只是显示图像,基本上杜绝了所有其他外挂(除了按键精灵,鼠标宏,手速挂等可以模拟玩家操作,捕捉像素计算操作,只能通过进程检测,举报,法律打击等其他方案)。&br&&br&而对于帧同步来说,我们同样可以在服务器验证完整的战斗逻辑。一般分为两种

我要回帖

更多关于 u3d主程 的文章

 

随机推荐