首页 > 学院 > 开发设计 > 正文

高并发、海量数据处理尽量少使用using也能提升效率

2019-11-17 02:48:48
字体:
来源:转载
供稿:网友

高并发、海量数据处理尽量少使用using也能提升效率

刚开始看到这个标题,估计很多人都云里雾里的。

  请看下面两段:

第一种方式:

                MemoryStream stream = new MemoryStream();          string text = "aasasdfasdfad;sas;fkqeworpkqwefkasdjfasdjf";                byte[] buff = System.Text.ASCIIEncoding.ASCII.GetBytes(text);                stream.Write(buff, 0, buff.Length);                stream.Flush();                stream.Close();                stream.Dispose();

第二种方式:

            string text = "aasasdfasdfad;sas;fkqeworpkqwefkasdjfasdjf";            using (MemoryStream stream = new MemoryStream())            {                byte[] buff = System.Text.ASCIIEncoding.ASCII.GetBytes(text);                stream.Write(buff, 0, buff.Length);                stream.Flush();                stream.Close();            }

不仅仅是我,估计一个老鸟程序员,大都会选择方法二,虽然方法一和方法二实现相同的功能,但是方法二带着套比较保险,即便我们失手,不会制造出垃圾来(这话听着怪怪的,能理解我在说什么就好)。之后,我在做一些消息处理机制的接收、处理、分发测试中,发现使用using关键字和不用using关键字,效率有着很大差异,不使用using关键字效率明显偏高,队列中缓存数据明显大减,而且基本不再出现容器不足溢出现象,这是为什么呢?答案马上揭晓。

以下是通过反汇编工具所得的一种类似汇编语言(如果以下真是汇编语言,就当我前面"类似"两字说错了,跟我当初学的汇编语言不一样。这个应该是.net架构可识别的中间语言)

.method PRivate hidebysig static void  Main(string[] args) cil managed{  .entrypoint  // 代码大小       65 (0x41)  .maxstack  4  .locals init ([0] string text,           [1] class [mscorlib]System.IO.MemoryStream 'stream',           [2] uint8[] buff)  IL_0000:  nop  IL_0001:  ldstr      "aasasdfasdfad;sas;fkqeworpkqwefkasdjfasdjf"  IL_0006:  stloc.0  IL_0007:  newobj     instance void [mscorlib]System.IO.MemoryStream::.ctor()  IL_000c:  stloc.1  IL_000d:  call       class [mscorlib]System.Text.Encoding [mscorlib]System.Text.Encoding::get_ASCII()  IL_0012:  ldloc.0  IL_0013:  callvirt   instance uint8[] [mscorlib]System.Text.Encoding::GetBytes(string)  IL_0018:  stloc.2  IL_0019:  ldloc.1  IL_001a:  ldloc.2  IL_001b:  ldc.i4.0  IL_001c:  ldloc.2  IL_001d:  ldlen  IL_001e:  conv.i4  IL_001f:  callvirt   instance void [mscorlib]System.IO.Stream::Write(uint8[],                                                                       int32,                                                                       int32)  IL_0024:  nop  IL_0025:  ldloc.1  IL_0026:  callvirt   instance void [mscorlib]System.IO.Stream::Flush()  IL_002b:  nop  IL_002c:  ldloc.1  IL_002d:  callvirt   instance void [mscorlib]System.IO.Stream::Close()  IL_0032:  nop  IL_0033:  ldloc.1  IL_0034:  callvirt   instance void [mscorlib]System.IO.Stream::Dispose()  IL_0039:  nop  IL_0040:  ret} // end of method Program::Main

以上是方法一,所得中间语言,看起来非常干净、流畅。下面看看方法二的:

.method private hidebysig static void  Main(string[] args) cil managed{  .entrypoint  // 代码大小       79 (0x4f)  .maxstack  4  .locals init ([0] string text,           [1] class [mscorlib]System.IO.MemoryStream 'stream',           [2] uint8[] buff,           [3] bool CS$4$0000)  IL_0000:  nop  IL_0001:  ldstr      "aasasdfasdfad;sas;fkqeworpkqwefkasdjfasdjf"  IL_0006:  stloc.0  IL_0007:  newobj     instance void [mscorlib]System.IO.MemoryStream::.ctor()  IL_000c:  stloc.1  .try  {    IL_000d:  nop    IL_000e:  call       class [mscorlib]System.Text.Encoding [mscorlib]System.Text.Encoding::get_ASCII()    IL_0013:  ldloc.0    IL_0014:  callvirt   instance uint8[] [mscorlib]System.Text.Encoding::GetBytes(string)    IL_0019:  stloc.2    IL_001a:  ldloc.1    IL_001b:  ldloc.2    IL_001c:  ldc.i4.0    IL_001d:  ldloc.2    IL_001e:  ldlen    IL_001f:  conv.i4    IL_0020:  callvirt   instance void [mscorlib]System.IO.Stream::Write(uint8[],                                                                         int32,                                                                         int32)    IL_0025:  nop    IL_0026:  ldloc.1    IL_0027:  callvirt   instance void [mscorlib]System.IO.Stream::Flush()    IL_002c:  nop    IL_002d:  ldloc.1    IL_002e:  callvirt   instance void [mscorlib]System.IO.Stream::Close()    IL_0033:  nop    IL_0034:  nop    IL_0035:  leave.s    IL_0047  }  // end .try  finally  {    IL_0037:  ldloc.1    IL_0038:  ldnull    IL_0039:  ceq    IL_003b:  stloc.3    IL_003c:  ldloc.3    IL_003d:  brtrue.s   IL_0046    IL_003f:  ldloc.1    IL_0040:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()    IL_0045:  nop    IL_0046:  endfinally  }  // end handler  IL_0047:  pop  IL_0048:  ret} // end of method Program::Main

(红字部分)这下能看出问题来了吧,本来是功能相同的两段代码,但是在方法二中,多出了一个try..finally模块,多出一个初始存储元的申请CS$4$0000,多出很多行相对来说算是赋址操作。这就是导致方法二效率低的主要原因。(删除这段的原因是大家都拿着我给的例子测试,其实我只是把一个大的功能缩小到这么小,来说明一个问题)

  但是刚刚我们也提到了,虽然方法一和方法二实现相同的功能,但是方法二带着套比较保险,即便我们失手,不会制造出垃圾来。即使是你忘记使用.close()、.dispose()方法释放资源,using还是会自动帮你处理好你遗忘的的坏事。

  所以在一般不要求高效开发中,尽量使用using,但是在处理高并发、海量数据等等情况下,尽量不要让using出现。不过现在好了,自从接触erlang后,它处理消息确实比C#/java/C++高效多了。


try..catch有一定的代码优化能力,少量代码测试,try..catch可能更优


  消息太多,直接导入数据库影响性能,就像你说的那样。大部分消息暂时保存在消息接收的服务端,少量重要消息分发到内网服务端再处理,至于保存的消息文本是在静夜访问流量少时处理。问题的关键不是和数据库或者数据缓冲层的交互,是消息泵接收分析消息的速度会影响到消息队列是否溢出,如果消息队列被阻塞,不仅是会丢掉消息那么简单,消息服务假死,以前很笨拙的方法就是把消息队列清空,但是明显这么做是不正确的,必须要从效率上进行优化。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表