CPU精简指令集和复杂指令集的区别

经常看到计算机课程上介绍PowerPC是采用精简指令集的CPU,酷睿CPU是复杂指令集。那么到底精简指令集和复杂指令集有什么区别呢?

以下内容摘自百度百科:

在计算机指令系统的优化发展过程中,出现过两个截然不同的优化方向:CISC技术和RISC技术。CISC是指复杂指令系统计算机(Complex Instruction Set Computer);RISC是指精减指令系统计算机(Reduced Instruction Set Computer)。这里的计算机指令系统指的是计算机的最低层的机器指令,也就是CPU能够直接识别的指令。随着计算机系统的复杂,要求计算机指令系统的构造能使计算机的整体性能更快更稳定。最初,人们采用的优化方法是通过设置一些功能复杂的指令,把一些原来由软件实现的、常用的功能改用硬件的指令系统实现,以此来提高计算机的执行速度,这种计算机系统就被称为复杂指令系统计算机,即Complex Instruction Set Computer,简称CISC。另一种优化方法是在20世纪80年代才发展起来的,其基本思想是尽量简化计算机指令功能,只保留那些功能简单、能在一个节拍内执行完成的指令,而把较复杂的功能用一段子程序来实现,这种计算机系统就被称为精简指令系统计算机.即Reduced Instruction Set Computer,简称RISC。RISC技术的精华就是通过简化计算机指令功能,使指令的平均执行周期减少,从而提高计算机的工作主频,同时大量使用通用寄存器来提高子程序执行的速度。

通过上述内容大家基本可以知道,复杂指令集就是将更多功能步骤集成在了CPU中。例如烹饪西红柿鸡蛋的步骤包括:购买西红柿和鸡蛋,清洗食材,打鸡蛋,炒鸡蛋,放西红柿继续炒,放糖,放盐,炒熟之后盛盘上桌。这样已连续的步骤被集成在CPU内部。外部程序需要烹饪西红柿鸡蛋的时候只需要向CPU下达指令说:“烹饪西红柿鸡蛋”就可以了。复杂指令集就是将琐碎的步骤实现集成到了CPU内部,例如INTEL的SSE3等。

精简指令集就是在CPU中只有容器,调料等基本指令。需要人们在软件中写上如何协调这些指令的步骤,例如你需要向CPU下达指令说:买西红柿,清晰食材,打鸡蛋,炒鸡蛋,放西红柿继续炒,放糖,放盐,炒熟之后盛盘上桌。

由此可见当两个人比赛做饭的时候,复杂指令集的参赛者只需要不停的说“做饭做饭”就可以了。而精简指令集的参赛者需要不停的重复做饭的整个过程和步骤。如果精简指令集的参赛者嘴巴够快才能赶上复杂指令集的参赛者,但是这个“嘴巴”其实取决于内存和CPU之间的带宽是否足够。当然精简指令集也同样存在优越性,复杂指令集要通过不断增加指令的复杂程度和指令的数量来提高性能所以才会越做越大越做越耗电,而精简指令集相比较无疑体积更小更加省电。

上面只是举了一个较为偏激的例子而已,你可以认为是针对于嵌入式精简指令集和普通酷睿(X86)架构的一个比较,这个是不对等和不公平的。IBM PowerPC可是堪比至强性能的呢,这是怎么回事呢?IBM在70年代末期提出复杂指令集存在很多缺点:1,随着应用需求,复杂指令集不可能无止境的增加指令。2,实际程序运行过程中80%的指令,只占一个处理器指令系统的20%,被频繁使用的指令只是一些取、存和加这些最简单的指令。3,CPU厂商不同,复杂指令集也不同,程序的可移植性会非常差,即便可以运行效率也会相差较大(所以我常说服务器要用INTEL处理器,因为更多的程序以调用INTEL指令集为依据)。针对复杂指令集的弊端才提出了精简指令集。

IBM PowerPC无疑拥有更强劲的处理性能与更大的内存带宽,但是其精简指令集的CPU决定了只能在某个特定应用领域才能完胜至强。因为PowerPC本身硬件设计和软件设计更具备针对性。例如并发控制、数据存取。

总结:精简指令集也好,复杂指令集也罢都是CPU运行功能和实现应用的方法而已。在特定领域和行业选择不同指令集CPU才是王道。手机和火星登陆车里边永远无法放进去X86,个人家用电脑日趋强劲的多应用多功能化也永远不要奢望使用IBM PowerPC。

有人说精简指令集架构平台下对于程序员的要求会更高呢?其实未必。在写程序时精简指令集和复杂指令集开发代码上并没有特别大的差异,真正转换成特定CPU指令架构底层语言是依靠编译器实现的。也就是你的代码技能在精简指令集用,也能在复杂指令集用,主要取决于你的编译器编译出的汇编语言适用于何种架构。

马化腾:腾讯14年,制胜的7个维度

编者按:腾讯公司首席执行官马化腾近日在《牛津管理评论》分享了他一直以来的思考。这些思考来自腾讯14年来的经验和教训。马化腾说,在腾讯内部的产品开发和运营过程中,有一个词一直被反复提及,那就是”灰度”。他很尊敬的企业家前辈任正非也曾经从这个角度有深入思考,并且写过《管理的灰度》,这里所提倡的灰度,主要是内部管理上的妥协和宽容。
以下为马化腾分享的全文:
从去年合作伙伴大会到现在,已经过去了一年。这一年里,我们大家一起向一个开放的、没有疆界的互联网新生态迈出了第一步。大量的创业伙伴在腾讯开放平台上涌现出来,其中不少团队还取得了初步成功。 Continue reading “马化腾:腾讯14年,制胜的7个维度”

冒择入希快归堆等九种排序算法介绍

昨晚听尚学堂的一个视频,其中主持人有说到几种排序算法的记忆口诀“冒择路(入)兮(希)快归堆”,抽着中午休息的空档,我在这里把这七种排序算法,外加另外2种:桶式排序和基数排序,一并使用Java语言进行简单的介绍。

冒泡排序,选择排序,插入排序,稀尔排序,快速排序,归并排序,堆排序,桶式排序,基数排序

一、冒泡排序(BubbleSort)

1. 基本思想:

两两比较待排序数据元素的大小,发现两个数据元素的次序相反时即进行交换,直到没有反序的数据元素为止。 Continue reading “冒择入希快归堆等九种排序算法介绍”

.NET中如何使用嵌入的资源

.Net中嵌入资源(位图、图标或光标等)有两种方式,一是直接把资源文件加入到项目,作为嵌入资源,在代码中通过Assembly的GetManifestResourceStream方法获取资源的Stream。另一种方法是在项目中加入. resx资源文件,在资源文件中添加资源,由ResourceManager类统一管理其中的资源。下面分别详述这两种方法:

使用GetManifestResourceStream读取嵌入资源

  1. 加入资源文件

    直接把要嵌入到程序集的资源文件加入到项目中,可以加在项目的根目录,可以加在项目的任何目录中。

  2. 设置资源文件的“BuildAction”属性

    将嵌入资源文件的“BuildAction”属性设置为“Embedded Resource”

  3. 代码中使用嵌入资源

//获得正在运行类所在的名称空间

Type type = MethodBase.GetCurrentMethod().DeclaringType;

string _namespace = type.Namespace;

//获得当前运行的Assembly

Assembly _assembly = Assembly.GetExecutingAssembly();

//根据名称空间和文件名生成资源名称

string resourceName = _namespace + ".directory.BitmapManifest.bmp";

//根据资源名称从Assembly中获取此资源的Stream

Stream stream = _assembly.GetManifestResourceStream(resourceName);

Image myImage = Image.FromStream(stream);

上述代码中有部分步骤是为了获得resourceName的值,resourceName的值结构形式类似于:”命名空间.目录路径.文件名+后缀”

此外还有一种访问资源的格式:”assembly://SpringSample/Sample.Spring/Resources.BitmapManifest.bmp”,有点像URI格式,不同的是协议为”assembly://”,”SpringSample”为程序集名称,”Sample.Spring”为默认命名空间,”Resources”为目录路径。注意:程序集名称与默认命名空间之间、默认命名空间与目录路径之间用”/”分隔,目录路径与文件名之间用”.”分隔,因为如此我们理解了访问资源的路径方式,就可以直接进行引用了。

使用. resx资源文件嵌入资源

  • 新建资源文件

    在项目中新建一个资源文件,资源文件以.resx为后缀,同时还会新建一个跟资源文件同名的Designer.cs文件。
    其实资源文件最大的用处是用来做多语言版本的软件时保存不同语言的资源,比如不同语言的菜单文本,可以把不同语言的字符串放在同一个资源类型下的不同资源包中,程序运行时根据运行时系统的culture选择不同的包显示不同语言的字符串。
    新建了资源文件后就能往资源文件中添加资源文件:

    资源中可以添加字符串、位图、图标、音频、文件等等的资源。
    添加的资源都会被保存在项目的Resources文件夹中。

  • 设置资源文件的“BuildAction”属性

    Resources文件夹中的所有资源文件的“BuildAction”属性设置为“Embedded Resource”。

  • 资源存在方式

    .resx资源文件管理的资源可以用两种存在形式,一种是以一般的文件形式存在于Resources文件夹中,另一个是经过Base64编码后嵌入到.resx资源文件中。
    打开.resx资源文件,选择资源,在属性中Persistence属性决定资源的存在形式。资源的两种存在形式,在代码中调用都是一样的。

  • 代码中使用嵌入资源
    Icon myIcon = (Icon)Resource1.ResourceManager.GetObject("IconTest");
    Icon myIcon = Resource1.MyIcon
  • 多语言的资源应用

    //得到当前语言环境
    CultureInfo ci = Thread.CurrentThread.CurrentCulture;
    //CultureInfo ci = System.Globalization.CultureInfo.CurrentCulture;
    
    Icon myIcon = (Icon)Resource1.ResourceManager("IconText", ci);

设计模式:抽象工厂模式(Abstract Factory)

概述

在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时由于需求的变化,往往存在着更多系列对象的创建工作。如何应对这种变化?如何绕过常规的对象的创建方法(new),提供一种“封装机制”来避免客户程序和这种“多系列具体对象创建工作”的紧耦合?这就是我们要说的抽象工厂模式。

意图

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

模型图

逻辑模型:

Continue reading “设计模式:抽象工厂模式(Abstract Factory)”

浅谈C#中子类用new与override的区别

我们先看代码和运行结果,代码:

BaseClass.cs文件:

    public class BaseClass
    {
        public BaseClass()
        {
            Console.WriteLine("Base Constructed Function");

        }

        public virtual void Execute()
        {
            Console.WriteLine("Base Virtual Execute Function");
        }

        public virtual void Execute2()
        {
            Console.WriteLine("Base Virtual Execute2 Function");
        }

    }

ChildClass.cs文件:

    public class ChildClass : BaseClass
    {
        public ChildClass()
        {
            Console.WriteLine("Children Constructed Function");
        }

        public override void Execute()
        {
            Console.WriteLine("Children Execute Function");
        }

        public new void Execute2()
        {
            Console.WriteLine("Children Execute2 Function");
        }

    }

Program.cs文件:

    class Program
    {
        static void Main(string[] args)
        {
            #region 直接创建子类对象
            ChildClass A = new ChildClass();
            A.Execute();
            A.Execute2();
            #endregion

            #region 使用父类型引用子类型
            BaseClass B = new ChildClass();
            B.Execute();
            B.Execute2();
            #endregion

            Console.ReadKey();
        }
    }

运行结果:

我们有发现:

C# override,重写,是指对父类中的虚方法(标记virtual)或抽象方法(标记为abstract)进行重写,实现新的功能,它必须与父类方法的签名完全一致,而且与父类方法的可访问性也必须一致,此关键字不可以用于重写非虚方法和静态方法,。

new,隐藏,是指在子类中重新定义一个签名与父类方法相同的方法,父类的同名方法只是被隐藏而未被覆盖,这个方法也可以不显示使用new修饰,只是编译时会弹出一个警告信息:如果是有意隐藏,请使用关键字new。

SqlServer,MySql如何获得最新自增长字段的值

在向数据库中多个表同时插入修改数据的时候,我们1般需要使用事务来保证完整性,这段时间在维护1个银行项目,其中有较多的同时插入修改多张数据表的场景,作者使用的主键是nvarchar类型,由C# Guid.NewGuid()方法每次生成随机GUID进行填充,然后将该GUID作为主键与关链键(外键)同时插入多张数据表中。

根据我有限的数据库原理知识,这样的设计可以保证记录的唯一性,毕竟GUID重复的机率比宇宙灭亡还难见到,但这样设计会降低查询速率,因为我们知道自增长的主键,在设计的时候使用了数据结构中的顺序存储结构,即我们只需要知道0记录的地址A,第20条主键记录的位置就在A+(主键数据类型长度*20)上,查询效率可谓是数据库索引中最快的,而nvarchar主键是很慢的,不过主键应该都是簇索引的吧。

那么我们在同时向多张数据表中插入数据,并且需要维护外键的时候,该如何获得之前插入的最后1个自增长数据值呢?总不能”select top 1 * from tablename order by pkname desc”吧?其实不必这么复杂,数据库设计者们给我们提供了更简单的方法:

SQL SERVER中的三种获得自增长ID的方法

先看例子:

      insert into users(Code,name) values('1111','aaaa')
      select  SCOPE_IDENTITY()
      select  @@IDENTITY
      select  IDENT_CURRENT('users')

三种方法的区别:

SCOPE_IDENTITY()
返回插入到同一作用域中的 IDENTITY 列内的最后一个 IDENTITY 值。一个作用域就是一个模块――存储过程、触发器、函数或批处理。因此,如果两个语句处于同一个存储过程、函数或批处理中,则它们位于相同的作用域中。

@@IDENTITY
返回最后插入的标识值,跨表跨会话。

IDENT_CURRENT(表名)
返回为任何会话和任何作用域中的指定表最后生成的标识值。这个函数需要一个以表名为值的变量,也就是说虽然不受会话和作用域的限制,却会受到表的限制。

体会:加上事物处理,两个函数一个变量没有本质区别。不加事物处理两个函数一个变量受到其他会话、作用域的影响不一样。

MySQL中获得自增长的方法

在MySQL中,使用auto_increment类型的id字段作为表的主键。通常的做法,是通过“select max(id) from tablename”的做法,但是显然这种做法需要考虑并发的情况,需要在事务中对主表加以“X锁“,待获得max(id)的值以后,再解锁。这种做法需要的步骤比较多,有些麻烦,而且并发性也不好。有没有更简单的做法呢?答案之一是通过select LAST_INSERT_ID()这个操作。乍一看,它和select max(id)很象,但实际上它是线程安全的。也就是说它是具体于数据库连接的。下面通过实验说明:

  1. 在连接1中向A表插入一条记录,A表包含一个auto_increment类型的字段。
  2. 在连接2中向A表再插入一条记录。
  3. 结果:在连接1中执行select LAST_INSERT_ID()得到的结果和连接2中执行select LAST_INSERT_ID()的结果是不同的;而在两个连接中执行select max(id)的结果是相同的。

其实在MSSQL中SCOPE_IDENTITY()和IDENT_CURRENT()的区别和这里是类似的。使用SCOPE_IDENTITY()可以获得插入某个IDENTITY字段的当前会话的值,而使用IDENT_CURRENT()会获得在某个IDENTITY字段上插入的最大值,而不区分不同 的会话。

注意:使用select last_insert_id()时要注意,当一次插入多条记录时,只是获得第一次插入的id值。

ASP.NET ViewState初探

话说在新公司上班快2周了,这里的工作和业务还是有些意思和挑战的。这几天1直在重构公司之前的一个项目,出于保密协议这里不能提项目名称,作为对新人的关爱,我仅负责其中1个模块的1个页面,这个页面的性能有些问题,当大批量进行数据修改的时候,提交和响应会非常的慢,我需要做的是就是改善它的性能。

花了一天时间分析了这个页面的有关代码,实在很头痛,大量的服务端控件、大量的事件、大量的重复代码,发现问题的关键在于该页大量的服务端控件(GridView嵌套大量DropDownList、TextBox、CheckBox)及大量的迭代查询。

于是狠心下来进行重构,越深入发现问题越多,根本无法重构,除非整个模块和某些底层推倒重来,但是工时将纠人心窝(明早开会把情况说明PM估计要跳的了)。

这个项目通过微软传统的WebForm Code Behind编程模型,大量使用事件和服务端控件,说到服务端控件,有个很重要的属性EnableViewState,它保持着页面回转的状态,借这次Code Review的机会,将Asp.Net ViewState进行一次复习。

ASP.NET ViewState 初探


ViewState 到底是什么

与刚接触 ASP.NET 页面的开发人员交谈时,他们通常向我提出的第一个问题就是:“那个 ViewState 到底是什么?”他们的语气中流露出的那种感觉,就象我来到一家异国情调的餐馆,侍者端上一道我从未见过的菜肴时的那种感觉 —— 既疑惑不解,又充满好奇。但肯定有人认为它不错,否则就不会提供了。所以,我会先尝一尝,或许会喜欢上它,尽管它看上去的确很古怪!
对于 ViewState 也是如此,但是如果适应了它的风格,您会发现在许多情况下,您将乐于在自己的 ASP.NET 应用程序中使用 ViewState,因为它可以帮助您使用更少的代码完成更多的工作。但是,有时也会对 ViewState 完全弃之不用。下面我们就这两种情况分别进行阐述,不过,让我们先回答什么是 ViewState 这个问题。
答案:ViewState 用于维护页面的 UI 状态
Web 是没有状态的,ASP.NET 页面也没有状态,它们在到服务器的每个往返过程中被实例化、执行、呈现和处理。作为 Web 开发人员,您可以使用众所周知的技术(如以会话状态将状态存储在服务器上,或将页面回传到自身)来添加状态。下面我们以图 1 中的注册窗体为例进行论述。

Continue reading “ASP.NET ViewState初探”

多线程应用中使用静态方法是否有线程安全问题

类的成员分为两类,静态成员(static member)和实例成员(instance member)。静态成员属于类,实例成员则属于对象,即类的实例。

简单讨论一下在一个类中使用静态字段(static field)和静态方法(static method)是否会有线程安全问题。

我们知道, 静态字段(static field)和静态方法(static method)的调用是通过类来调用。静态方法不对特定的实例操作。实例方法可对特定的实例操作,既能访问静态成员,也能访问实例成员。

那么,在多线程中使用静态方法是否有线程安全问题?这要看静态方法是是引起线程安全问题要看在静态方法中是否使用了静态成员。

因为,在多线程中使用同一个静态方法时,每个线程使用各自的实例字段(instance field)的副本,而共享一个静态字段(static field)。所以说,如果该静态方法不去操作一个静态成员,只在方法内部使用实例字段(instance field),不会引起安全性问题。但是,如果该静态方法操作了一个静态字段,则需要静态方法中采用互斥访问的方式进行安全处理。

静态变量前加volitile,静态函数里面使用Lock控制线程安全。

对于ASP.NET Web应用程序, 多个客户端访问服务端, 就是一个多线程的例子。

C#运算符关键字 – AS运算符

从这一篇开始,我将为大家带来一些C#运算符关键字,我们时常会用到它们,但是可能只知其然不知其所以然,所以整理出来,供大家参考:

as 运算符用于在兼容的引用类型之间执行某些类型的转换。 例如:

 class csrefKeywordsOperators
   {
       class Base
       {
           public override string  ToString()
           {
	             return "Base";
           }
       }
       class Derived : Base 
       { }

       class Program
       {
           static void Main()
           {

               Derived d = new Derived();

               Base b = d as Base;
               if (b != null)
               {
                   Console.WriteLine(b.ToString());
               }

           }
       }
   }

备注


as 运算符类似于强制转换操作。 但是,如果无法进行转换,则 as 返回 null 而非引发异常。 请看下面的表达式:

expression as type

它等效于以下表达式,但只计算一次 expression。

expression is type ? (type)expression : (type)null

注意,as 运算符只执行引用转换和装箱转换。 as 运算符无法执行其他转换,如用户定义的转换,这类转换应使用强制转换表达式来执行。

 

class ClassA { }
class ClassB { }

class MainClass
{
    static void Main()
    {
        object[] objArray = new object[6];
        objArray[0] = new ClassA();
        objArray[1] = new ClassB();
        objArray[2] = "hello";
        objArray[3] = 123;
        objArray[4] = 123.4;
        objArray[5] = null;

        for (int i = 0; i < objArray.Length; ++i)
        {
            string s = objArray[i] as string;
            Console.Write("{0}:", i);
            if (s != null)
            {
                Console.WriteLine("'" + s + "'");
            }
            else
            {
                Console.WriteLine("not a string");
            }
        }
    }
}
/*
Output:
0:not a string
1:not a string
2:'hello'
3:not a string
4:not a string
5:not a string
*/