上次我对C#类与结构体做了一次速度评测(http://blog.csdn.net/zyl910/article/details/6788417)。经过一段时间思索,发现还可以进一步探讨——

第一、栈变量。上次的“硬编码”,是访问类中的静态变量的。若改为访问函数中的栈变量,性能会不会有所提高?
第二、栈分配(stackalloc)。既然要测试栈变量,我们还可以顺便测试一下在栈上分配的内存块的访问性能。
第三、64位整数。由于32位系统的成功,我们已经习惯了使用32位整数(int)。现在64位系统逐渐普及,我们得为此做好准备。对于指针操作时经常要用到的偏移量增减运算来说,是使用32位整数,还是使用64位整数,或写两套代码?这需要测试后才能决定。
第四、密封类(sealed)。听说密封类能提高性能,我们可以测试一下。有两种测试方式,一是为原来的派生类增加sealed关键字,二是专门另外写一个密封类。我决定同时使用这两种方法,分别测试其性能。

一、测试代码

  测试代码如下——

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;namespace TryPointerCall
{/// <summary>/// 指针操作接口/// </summary>public interface IPointerCall{/// <summary>/// 指针操作/// </summary>/// <param name="p">源指针</param>/// <returns>修改后指针</returns>unsafe byte* Ptr(byte* p);}#region 非泛型/// <summary>/// [非泛型] 指针操作基类/// </summary>public abstract class PointerCall : IPointerCall{public abstract unsafe byte* Ptr(byte* p);}/// <summary>/// [非泛型] 指针操作派生类: 指针+偏移/// </summary>public sealed class PointerCallAdd : PointerCall{/// <summary>/// 偏移值/// </summary>public int Offset = 0;public override unsafe byte* Ptr(byte* p){return unchecked(p + Offset);}}/// <summary>/// [非泛型] 指针操作密封类: 指针+偏移/// </summary>public sealed class SldPointerCallAdd : IPointerCall{/// <summary>/// 偏移值/// </summary>public int Offset = 0;public unsafe byte* Ptr(byte* p){return unchecked(p + Offset);}}/// <summary>/// [非泛型] 指针操作结构体: 指针+偏移/// </summary>public struct SPointerCallAdd : IPointerCall{/// <summary>/// 偏移值/// </summary>public int Offset;public unsafe byte* Ptr(byte* p){return unchecked(p + Offset);}}#endregion#region 泛型// !!! C#不支持将整数类型作为泛型约束 !!!//public abstract class GenPointerCall<T> : IPointerCall where T: int, long//{//    public abstract unsafe byte* Ptr(byte* p);//    void d()//    {//    }//}#endregion#region 全部测试/// <summary>/// 指针操作的一些常用函数/// </summary>public static class PointerCallTool{
#if DEBUGprivate const int CountLoop = 10000000;   // 循环次数
#elseprivate const int CountLoop = 200000000;  // 循环次数
#endif/// <summary>/// 调用指针操作/// </summary>/// <typeparam name="T">具有IPointerCall接口的类型。</typeparam>/// <param name="ptrcall">调用者</param>/// <param name="p">源指针</param>/// <returns>修改后指针</returns>public static unsafe byte* CallPtr<T>(T ptrcall, byte* p) where T : IPointerCall{return ptrcall.Ptr(p);}public static unsafe byte* CallClassPtr<T>(T ptrcall, byte* p) where T : PointerCall{return ptrcall.Ptr(p);}public static unsafe byte* CallRefPtr<T>(ref T ptrcall, byte* p) where T : IPointerCall{return ptrcall.Ptr(p);}// C#不允许将特定的结构体作为泛型约束。所以对于结构体只能采用上面那个方法,通过IPointerCall接口进行约束,可能会造成性能下降。//public static unsafe byte* SCallPtr<T>(T ptrcall, byte* p) where T : SPointerCallAdd//{//    return ptrcall.Ptr(p);//}private static int TryIt_Static_Offset;private static unsafe byte* TryIt_Static_Ptr(byte* p){return unchecked(p + TryIt_Static_Offset);}/// <summary>/// 执行测试 - 静态调用/// </summary>/// <param name="sOut">文本输出</param>private static unsafe void TryIt_Static(StringBuilder sOut, int CountLoop){TryIt_Static_Offset = 1;// == 性能测试 ==byte* p = null;Stopwatch sw = new Stopwatch();int i;unchecked{#region 测试// 硬编码.栈变量int iOffset = 1;sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = p + iOffset;}sw.Stop();sOut.AppendLine(string.Format("硬编码.栈变量:\t{0}", sw.ElapsedMilliseconds));// 硬编码.栈分配int* pOffset = stackalloc int[1];pOffset[0] = 1;sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = p + pOffset[0];}sw.Stop();sOut.AppendLine(string.Format("硬编码.栈分配:\t{0}", sw.ElapsedMilliseconds));// 硬编码.静态sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = p + TryIt_Static_Offset;}sw.Stop();sOut.AppendLine(string.Format("硬编码.静态:\t{0}", sw.ElapsedMilliseconds));// 静态调用sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = TryIt_Static_Ptr(p);}sw.Stop();sOut.AppendLine(string.Format("静态调用:\t{0}", sw.ElapsedMilliseconds));#endregion // 测试}}private static long TryIt_Static64_Offset;private static unsafe byte* TryIt_Static64_Ptr(byte* p){return unchecked(p + TryIt_Static64_Offset);}/// <summary>/// 执行测试 - 静态调用/// </summary>/// <param name="sOut">文本输出</param>private static unsafe void TryIt_Static64(StringBuilder sOut, int CountLoop){TryIt_Static64_Offset = 1;// == 性能测试 ==byte* p = null;Stopwatch sw = new Stopwatch();int i;unchecked{#region 测试// 硬编码.栈变量long iOffset = 1;sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = p + iOffset;}sw.Stop();sOut.AppendLine(string.Format("64硬编码.栈变量:\t{0}", sw.ElapsedMilliseconds));// 硬编码.栈分配long* pOffset = stackalloc long[1];pOffset[0] = 1;sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = p + pOffset[0];}sw.Stop();sOut.AppendLine(string.Format("64硬编码.栈分配:\t{0}", sw.ElapsedMilliseconds));// 硬编码.静态sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = p + TryIt_Static64_Offset;}sw.Stop();sOut.AppendLine(string.Format("64硬编码.静态:\t{0}", sw.ElapsedMilliseconds));// 静态调用sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = TryIt_Static64_Ptr(p);}sw.Stop();sOut.AppendLine(string.Format("64静态调用:\t{0}", sw.ElapsedMilliseconds));#endregion // 测试}}/// <summary>/// 执行测试 - 非泛型/// </summary>/// <param name="sOut">文本输出</param>private static unsafe void TryIt_NoGen(StringBuilder sOut, int CountLoop){// 创建PointerCallAdd pca = new PointerCallAdd();SldPointerCallAdd dpca = new SldPointerCallAdd();SPointerCallAdd spca;pca.Offset = 1;spca.Offset = 1;// 转型PointerCall pca_base = pca;IPointerCall pca_itf = pca;IPointerCall dpca_itf = dpca;IPointerCall spca_itf = spca;// == 性能测试 ==byte* p = null;Stopwatch sw = new Stopwatch();int i;unchecked{#region 调用#region 直接调用// 调用派生类sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = pca.Ptr(p);}sw.Stop();sOut.AppendLine(string.Format("调用派生类:\t{0}", sw.ElapsedMilliseconds));// 调用密封类sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = dpca.Ptr(p);}sw.Stop();sOut.AppendLine(string.Format("调用密封类:\t{0}", sw.ElapsedMilliseconds));// 调用结构体sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = spca.Ptr(p);}sw.Stop();sOut.AppendLine(string.Format("调用结构体:\t{0}", sw.ElapsedMilliseconds));#endregion  // 直接调用#region 间接调用// 调用基类sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = pca_base.Ptr(p);}sw.Stop();sOut.AppendLine(string.Format("调用基类:\t{0}", sw.ElapsedMilliseconds));// 调用派生类的接口sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = pca_itf.Ptr(p);}sw.Stop();sOut.AppendLine(string.Format("调用派生类的接口:\t{0}", sw.ElapsedMilliseconds));// 调用密封类的接口sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = dpca_itf.Ptr(p);}sw.Stop();sOut.AppendLine(string.Format("调用密封类的接口:\t{0}", sw.ElapsedMilliseconds));// 调用结构体的接口sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = spca_itf.Ptr(p);}sw.Stop();sOut.AppendLine(string.Format("调用结构体的接口:\t{0}", sw.ElapsedMilliseconds));#endregion    // 间接调用#endregion   // 调用#region 泛型调用#region 泛型基类约束// 基类泛型调用派生类sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = CallClassPtr(pca, p);}sw.Stop();sOut.AppendLine(string.Format("基类泛型调用派生类:\t{0}", sw.ElapsedMilliseconds));// 基类泛型调用基类sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = CallClassPtr(pca_base, p);}sw.Stop();sOut.AppendLine(string.Format("基类泛型调用基类:\t{0}", sw.ElapsedMilliseconds));#endregion // 泛型基类约束#region 泛型接口约束 - 直接调用// 接口泛型调用派生类sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = CallPtr(pca, p);}sw.Stop();sOut.AppendLine(string.Format("接口泛型调用派生类:\t{0}", sw.ElapsedMilliseconds));// 接口泛型调用密封类sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = CallPtr(dpca, p);}sw.Stop();sOut.AppendLine(string.Format("接口泛型调用密封类:\t{0}", sw.ElapsedMilliseconds));// 接口泛型调用结构体sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = CallPtr(spca, p);}sw.Stop();sOut.AppendLine(string.Format("接口泛型调用结构体:\t{0}", sw.ElapsedMilliseconds));// 接口泛型调用结构体引用sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = CallRefPtr(ref spca, p);}sw.Stop();sOut.AppendLine(string.Format("接口泛型调用结构体引用:\t{0}", sw.ElapsedMilliseconds));#endregion   // 直接调用#region 间接调用// 接口泛型调用基类sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = CallPtr(pca_base, p);}sw.Stop();sOut.AppendLine(string.Format("接口泛型调用基类:\t{0}", sw.ElapsedMilliseconds));// 接口泛型调用派生类的接口sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = CallPtr(pca_itf, p);}sw.Stop();sOut.AppendLine(string.Format("接口泛型调用派生类的接口:\t{0}", sw.ElapsedMilliseconds));// 接口泛型调用密封类的接口sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = CallPtr(dpca_itf, p);}sw.Stop();sOut.AppendLine(string.Format("接口泛型调用密封类的接口:\t{0}", sw.ElapsedMilliseconds));// 接口泛型调用结构体的接口sw.Reset();sw.Start();for (i = 0; i < CountLoop; ++i){p = CallPtr(spca_itf, p);}sw.Stop();sOut.AppendLine(string.Format("接口泛型调用结构体的接口:\t{0}", sw.ElapsedMilliseconds));#endregion    // 间接调用#endregion   // 泛型调用}}/// <summary>/// 执行测试 - 泛型/// </summary>/// <param name="sOut">文本输出</param>private static unsafe void TryIt_Gen(StringBuilder sOut, int CountLoop){// !!! C#不支持将整数类型作为泛型约束 !!!}/// <summary>/// 执行测试/// </summary>public static string TryIt(){StringBuilder sOut = new StringBuilder();sOut.AppendLine("== PointerCallTool.TryIt() ==");TryIt_Static(sOut, CountLoop);TryIt_Static64(sOut, CountLoop);TryIt_NoGen(sOut, CountLoop);TryIt_Gen(sOut, CountLoop);sOut.AppendLine();return sOut.ToString();}/// <summary>/// 执行测试 - static/// </summary>public static string TryItStatic(){StringBuilder sOut = new StringBuilder();int cnt = CountLoop * 10;sOut.AppendLine("== PointerCallTool.TryItStatic() ==");TryIt_Static(sOut, cnt);TryIt_Static64(sOut, cnt);sOut.AppendLine();return sOut.ToString();}}
#endregion}

二、测试环境

  编译器——
VS2005:Visual Studio 2005 SP1。
VS2010:Visual Studio 2010 SP1。
采用上述编译器编译为Release版程序,最大速度优化。

  机器A——
HP CQ42-153TX
处理器:Intel Core i5-430M(2.26GHz, Turbo 2.53GHz, 3MB L3)
内存容量:2GB (DDR3-1066)

  机器B——
DELL Latitude E6320 
处理器:Intel i3-2310M(2.1GHz, 3MB L3)
内存容量:4GB (DDR3-1333,双通道)

  测试环境——
A_2005:机器A,VS2005,Window 7 32位。
A_2010:机器A,VS2010,Window 7 32位。
B_2005:机器B,VS2005,Window XP SP3 32位。
B_2010:机器B,VS2010,Window XP SP3 32位。
B64_2005:机器B,VS2005,Window 7 64位(x64)。
B64_2010:机器B,VS2010,Window 7 64位(x64)。

三、硬编码与静态调用 的测试结果(栈变量、栈分配、64位整数)

  因为硬编码与静态调用很可能会被执行函数展开优化,速度明显比其他测试项目要快。所我另外写了一个测试函数(TryItStatic),将循环次数设为原来的10倍。

  测试结果如下(单位:毫秒)——

模式 A_2005 A_2010 B_2005 B_2010 B64_2005 B64_2010
硬编码.栈变量: 1608 1623 957 966 960 959
硬编码.栈分配: 1612 1617 1073 957 961 960
硬编码.静态: 1609 1613 957 971 961 960
静态调用: 1608 1611 1063 958 961 963
64硬编码.栈变量: 1610 1617 967 957 959 1010
64硬编码.栈分配: 1610 1619 1034 957 960 1012
64硬编码.静态: 1609 1618 999 996 957 1010
64静态调用: 1610 1615 959 1002 957 7696

  结果分析——
先看32位与64位的区别。发现在大多数情况,32位与64位的速度是一样的。唯一就是64位整数运算代码在“64位平台+VS2010”上运行时,速度比在32位下还慢,尤其是静态调用慢了好几倍,硬编码代码的速度也有所下降。真的很奇怪,既然运行的是同一份程序,为什么64位比32位还慢,难道是.Net 4.0在x64平台上的即时编译器的问题?不解。
栈变量、栈分配、静态变量的访问速度几乎一致,看来可以放心地随意使用。

  看来以后写指针操作代码时,只写64位整数版就行了。

四、密封类 的测试结果

  测试结果如下(单位:毫秒)——
模式 A_2005 A_2010 B_2005 B_2010 B64_2005B64_2010
硬编码.栈变量: 162 162 95 95 96 95
硬编码.栈分配: 161 161 95 95 95 97
硬编码.静态: 161 165 97 95 97 95
静态调用: 161 163 95 95 96 97
64硬编码.栈变量: 161161989596 100
64硬编码.栈分配: 160162959795 100
64硬编码.静态: 162 162 95 97 95 100
64静态调用: 161 161 95 95 97 770
调用派生类: 563 568 670 668 676 580
调用密封类: 161 162 101 103 102 767
调用结构体: 163 161 116 102 191 772
调用基类: 566 573 668 660 675 577
调用派生类的接口: 727 731 767 862 862 770
调用密封类的接口: 721 730 957 862 870 771
调用结构体的接口: 104511341318134013441253
基类泛型调用派生类: 910795127478912561287
基类泛型调用基类: 902 785 1092 676 1346 1250
接口泛型调用派生类: 1407733163486216331633
接口泛型调用密封类: 1405808173395617431638
接口泛型调用结构体: 5661606711018641250
接口泛型调用结构体引用: 48016170098769961
接口泛型调用基类: 1409728176776416311635
接口泛型调用派生类的接口: 1410727170296617301634
接口泛型调用密封类的接口: 1402808171995816351637
接口泛型调用结构体的接口: 161711281859149922082117

  将测试结果重新排版一下,突出不同实现方法的速度区别——

环境 分类 基类 派生类 密封类 结构体 结构体的引用
A_2005 直接调用 566 563 161 163  
  接口调用   727 721 1045  
  基类约束泛型调用 902 910      
  接口约束泛型调用   1407 1405 566 480
  接口约束泛型调用接口 1409 1410 1402 1617  
A_2010 直接调用 573 568 162 161  
  接口调用   731 730 1134  
  基类约束泛型调用 785 795      
  接口约束泛型调用   733 808 160 161
  接口约束泛型调用接口 728 727 808 1128  
B_2005 直接调用 668 670 101 116  
  接口调用   767 957 1318  
  基类约束泛型调用 1092 1274      
  接口约束泛型调用   1634 1733 671 700
  接口约束泛型调用接口 1767 1702 1719 1859  
B_2010 直接调用 660 668 103 102  
  接口调用   862 862 1340  
  基类约束泛型调用 676 789      
  接口约束泛型调用   862 956 101 98
  接口约束泛型调用接口 764 966 958 1499  
B64_2005 直接调用 675 676 102 191  
  接口调用   862 870 1344  
  基类约束泛型调用 1346 1256      
  接口约束泛型调用   1633 1743 864 769
  接口约束泛型调用接口 1631 1730 1635 2208  
B64_2010 直接调用 577 580 767 772  
  接口调用   770 771 1253  
  基类约束泛型调用 1250 1287      
  接口约束泛型调用   1633 1638 1250 961
  接口约束泛型调用接口 1635 1634 1637 2117  

  综合来看,密封类的性能最好,在大多数测试项目中名列前茅——
“直接调用”时能被内联(inline)优化,与“硬编码”一样快,快于派生类。
“接口调用”、“泛型调用接口”时与派生类性能一致,快于结构体的“接口调用”。
唯一就是在“泛型调用”时,落后于结构体,与派生类差不多稍微慢一点。
再就是奇怪的“64位平台+VS2010”问题,密封类、结构体在直接调用时,还不如派生类。

  最后总结一下可能会被内联优化的调用类型——
32位平台+VS2005:调用密封类、调用结构体。
32位平台+VS2010:调用密封类、调用结构体、接口约束泛型调用结构体。
64位平台+VS2005:调用密封类、调用结构体。
64位平台+VS2010:(无)。

(完)

测试程序exe——
http://115.com/file/e6ymd5fe
http://download.csdn.net/detail/zyl910/3619643

源代码下载——
http://115.com/file/aqz167n9
http://download.csdn.net/detail/zyl910/3619647

目录——
C#类与结构体究竟谁快——各种函数调用模式速度评测:http://www.cnblogs.com/zyl910/archive/2011/09/19/2186623.html
再探C#类与结构体究竟谁快——考虑栈变量、栈分配、64位整数、密封类:http://www.cnblogs.com/zyl910/archive/2011/09/20/2186622.html
三探C#类与结构体究竟谁快——MSIL(微软中间语言)解读:http://www.cnblogs.com/zyl910/archive/2011/09/24/2189403.html
四探C#类与结构体究竟谁快——跨程序集(assembly)调用:http://www.cnblogs.com/zyl910/archive/2011/10/01/2197844.html

再探C#类与结构体究竟谁快——考虑栈变量、栈分配、64位整数、密封类相关推荐

  1. C#类与结构体究竟谁快——各种函数调用模式速度评测

    以前我一直有个疑惑--在C#中,究竟是类(class)比较快,还是结构体(struct)比较快? 当时没有深究. 最近我遇到一个难题,需要将一些运算大的指针操作代码给封装一下.原先为了性能,这些代码是 ...

  2. 自制深度学习推理框架-第十一节-再探Tensor类并构建计算图的图关系

    自制深度学习推理框架-第十一节-再探Tensor类并准备算子的输入输出 本课程介绍 我写了一个<从零自制深度学习推理框架>的课程,课程语言是 C++,课程主要讲解包括算子实现和框架设计的思 ...

  3. 64位整数乘法(类快速幂)

    题目链接 AcWing 90. 代码 #include <bits/stdc++.h>using namespace std;typedef long long ll;ll quick_m ...

  4. Swift傻傻分不清楚系列(十一)类和结构体

    本页包含内容: 类和结构体对比 结构体和枚举是值类型 类是引用类型 类和结构体的选择 字符串(String).数组(Array).和字典(Dictionary)类型的赋值与复制行为 类和结构体是人们构 ...

  5. Swift 类与结构体

    前言 类和结构体是人们构建代码所用的一种通用且灵活的构造体.我们可以使用完全相同的语法规则来为类和结构体定义属性(常量.变量)和添加方法,从而扩展类和结构体的功能. 与其他编程语言所不同的是,Swif ...

  6. 你真的了解:类与结构吗?(细谈类与结构)

    前言:在面向对象的动态编程中,封装已经成为了必不可少的需求,但是在封装时我们又会遇到结构和类这两种方法,那么它们有什么不同呢?我们分别在什么情况下使用它们呢?下面跟随脚步我们一起去一探究竟...... ...

  7. swift类和结构体

    2.9类和结构体 本页包含内容: 类和结构体对比 结构体和枚举是值类型 类是引用类型 类和结构体的选择 字符串.数组.和字典类型的赋值与复制行为 类和结构体是人们构建代码所用的一种通用且灵活的构造体. ...

  8. Swift 基本知识点之七类与结构体

    类和结构体对比 结构体和枚举是值类型 类是引用类型 类和结构体的选择 字符串(String).数组(Array).和字典(Dictionary)类型的赋值与复制行为 类和结构体是人们构建代码所用的一种 ...

  9. Swift-2.9类和结构体

    本页包含内容: 类和结构体对比 结构体和枚举是值类型 类是引用类型 类和结构体的选择 字符串(String).数组(Array).和字典(Dictionary)类型的赋值与复制行为 类和结构体是人们构 ...

最新文章

  1. 计算机组成算术流水线,计算机组成系统结构试题整理.doc
  2. 何时(不)使用Java抽象类
  3. python ansible_Ansible Python API | linux系统运维
  4. 7 款从 HTML 文档提取文本的工具
  5. GIS开发随笔(3)——ArcXML和NET_Link方法
  6. 每天一道LeetCode-----根据中序遍历和后序遍历重构二叉树
  7. Bootstrap3的输入框数字点击修改效果
  8. 多线程编程下单例模式与多例模式的使用总结
  9. 在ant中将依赖jar包一并打包的方法
  10. 移动开发框架,第【三】弹:Zepto.js
  11. STM32F205RET6工程应用要点
  12. android即时通信表情特效,微信英文代码表情特效-微信英文代码表情翻译特效大全v1.0 安卓版预约_飞翔下载...
  13. 电脑怎么把大量音频合并
  14. 安卓上的测试软件有哪些,手机硬件检测软件有哪些
  15. mbedtls学习4.mbedtls_RAM/ROM优化指南
  16. 24V电磁铁电磁特模块电路分析
  17. pmp 估算技术_现在是时候进行大型技术估算了
  18. Python使用-错误“name ‘requests‘ is not defined”的探查
  19. win10双显卡怎么切换amd和英特尔_手把手给你细说win10系统双显卡设置只使用独立显卡的流程...
  20. 超分算法小合集之SRCNN、DCSCN、SRDenseNet、SRGAN

热门文章

  1. Python 过程式编程与函数式编程
  2. qpsk调制解调matlab_本科毕业设计课题—QPSK相干解调的MATLAB仿真(3)
  3. 2018湖北计算机准考证打印,2018年3月湖北计算机等级考试准考证打印入口
  4. zabbix.php访问不了_zabbix_配置Nginx连接php
  5. axure 下拉多选 元件_Axure教程:下拉多选列表集合(多选下拉列表+单选下拉列表+分级下拉列表)...
  6. 如何评价LoRa这项应用于低功率长距离场景的物联网传输技术?
  7. 并查集 ---- 扩展域并查集判二分图 + 循环模拟字典树 The 2020 ICPC Asia Macau Regional Contest C. Club Assignment (详解)
  8. php m 报错,PHP框架ThinkPHP入参m报错
  9. java什么时候用list_Java快问快答:用 ArrayList 还是 LinkedList?
  10. luogu P5142 区间方差(线段树、乘法逆元)