赵翔鹏的Blog Xiangpeng's Thinkpad

12十一/093

Windows里跟performance相关的一些概念

1、kernel里的Cache Manager

提供了在ReadFile、WriteFile时的cache,包括read-ahead和write-behind机制。原理是把application本来应该让file system服务的I/O request截走,转给cache manager自己拥有的一小块memory。

Cache manager就像一个应用程序,它只管虚拟内存,真正的物理内存管理都由memory manager做。所以cache那一部分memory也可能被page out。

只针对普通的file,dll、exe文件不会read-ahead。更精确的说,凡是用memory-mapped file方式读取的文件,都不会被read-ahead。

2、Prefetch:

在启动一个Process时,总要load一些dll,常用的几个icon等。如果等用到了再去读就比较慢,而且硬盘磁头会来回跑路。prefetch会根据上次process运行的历史记录,按照它们在磁盘上的顺序预读这些dll。

因此,一个程序第一次运行时可能硬盘要转很久,但以后再运行就快了。Prefetch对Boot也有类似的优化,会自动defrag启动时用到的文件。

可能的问题:上次打开的文件这次未必用到。

3、SuperFetch

为了解决“after-lunch effect”引入的。为啥午饭回来之后outlook很迟钝,硬盘在狂转?因为在idle的时候杀毒软件开始扫描磁盘,占用大量物理内存,outlook不幸被page out了。等杀毒软件运行完释放了内存,LRU算法会把杀毒软件留在内存的standby list里,而outlook的页面却不会从pagefile里回来。

类似Prefetch,SuperFetch记录内存的历史使用情况。它考虑了时间信息,比如“每天下午2:00要用Outlook”,这样就预先把需要的东西读到内存里。而且也会考虑把常用/重要的东西(比如输密码解锁那段code)尽量留在内存里。

只要发现你的空闲内存比较大(比如刚有一个大程序退出),它就会一点一点地吃掉你的空闲内存,把它认为需要用的东西放在内存里。所以很多人误以为SuperFetch浪费内存。

4、ReadyBoost:

用优盘当虚拟内存。hard fault发生时,从优盘读比硬盘稍微能快一点点。

5、ReadyBoot:

在boot的时候,预读一些硬盘数据到内存里。这个跟prefetch很像但是更智能。我现在还不是很清楚这个东西怎么工作的。还需要翻一翻宝书Windows Internals 5。。。

Update: 今天翻了宝书,发现宝书上只用了1页描述ReadyBoot……郁闷,还是不清楚。这也意味着即使我通过别的方法把它搞清楚,也不能把结果贴出来了。

21二/095

C#和CLR的15个细节

这两周一直在training,一共听了4个课程,相当的累啊。

今天先把Jeffrey Richter的培训课:C# and CLR中讲到的一些东西整理一下:

  1. foreach的性能问题

    foreach(string s in rows) { foo(s); }的实现是:

  2. IEnumerator e = rows.GetEnumerator();
    try {
      string s;
      while (e.MoveNext()) {
        s = (String) e.Current;
        foo(s);
      }
    }
    finally {
      IDisposable d = e as IDisposable;
      if (d != null) d.Dispose();
    }

    每一步都调用了e.MoveNext()和e.Current两个方法;而大多数时候,完全有可能优化为一次调用。显然这对性能是有影响的。虽然foreach对于数组作了单独的优化(编译成for循环),但这还是值得注意的。

    那么,怎么做比较快?

    对于List等Collection,可以用ForEach(Action<T> action),FindAll(Predicate<T> match),ConvertAll<U>(Converter<T, U> converter)等方法。它们比较快,但不是所有实现IEnumerable的类都提供。

    LINQ追求compatiblity,而不是performance。因此LINQ的实现完全采用了foreach。值得注意。

  1. yield的实现原理

    实现一个支持IEnumerable的对象时,一般会用到yield关键字,这样foreach遍历这个对象时,可以做到lazy evaluation。例如:

    class MyCollection: IEnumerable<char> {
      private string s; ...
      public IEnumerable<char> GetEnumerator() {
        for (int i=0; i<s.Length; i++) {
          yield return s[i];
        }
      }
    }

    执行到yield时函数返回,下次调用时,接着上次运行的位置继续运行。这个continuation的效果是怎么做的呢?

    包含yield的函数都会被编译器做成一个状态机。每调一次,就接着上次的状态继续运行。简单有效啊。我一直以为要有什么特殊的办法呢。

  2. exception handling的实现决定了throw的performance较差。

    可以用Int32.TryParse代替try{Int32.Parse…}catch{…},稍快一点。类似地建议使用Dictionary.TryGetValue。

  3. .Net CLR执行引擎对应于MSCorWks.dll和MSCorEE.dll这两个文件。

  4. .Net 3.0, 3.5没有对CLR作任何修改。

    所有增加的东西(比如LINQ)都是syntactic sugar,只改了C#编译器而已。

  5. AppDomain

    如果把.Net虚拟机看成一个虚拟操作系统,AppDomain的概念则类似于操作系统中的进程。

    可以用代码创建一个AppDomain,然后动态加载/卸载assembly,还可以设置权限,相当于提供了一个沙箱。

    跨AppDomain的调用类似于RPC。

    调用某个AppDomain内部的obj.foo(x)时,.net会自动帮你做出一个proxy object,你所调用的obj其实是一个proxy object。传给foo的参数x会先被被marshal,以保证AppDomain被安全隔离。

    谁用AppDomain?SQL Server用这个技术实现managed存储过程。IIS会把不同的Web Application放在不同的AppDomain里,以实现动态装卸。

  6. 动态载入Assembly的陷阱

    Sytem.Reflection.Assembly.LoadFrom(pathName)并不会载入pathName所指定的dll,而是看看pathName那个dll的名字、版本,然后到系统默认位置去找。(陷阱啊)

  7. C#里用reflection创建一个新对象

    用Activator.CreateInstance。(奇怪的名字啊。)

  8. C#泛型之“where”

    可以用“where”来限定T的接口。例如

    static T min<T>(T arg1, T arg2) where T: IComparable<T> {…}

    不写where的话,就不能调arg1.CompareTo(arg2)。

    为啥不把T换成IComparable?一是为保证arg1, arg2一定是同一个类型,二是泛型的效率更高。(JIT会为不同类型的T各生成一份native code,从而避免了boxing)

    更多where的细节:

    * 要想调T t1 = new T(),必须声明where T: new()或者where T: struct

    * 要写T t2 = null,必须声明where T: class

    * T z = default(T)是一个特殊的用法,会把T的每个bit都置为0。

    * 假设定义了Foo<T>(T x, T y),则if (x==null) … 是可以通过的,虽然C#中value type的值不允许为null(例如int a=null是错的)。这是因为,此时的语义是一致的,反正if里面的操作不被执行就是了,所以编译器对这种特殊情况网开一面。

    * if (x==y)不行,除非写了where T: baseclass。(这里我也没理解为啥。。。>_<好像说是不知道应该用reference比较还是value比较?)

  9. 匿名函数的背后。。。

    在C# 2.0以后可以用匿名的delegate,如ThreadPool.QueueWorkItem(delegate (Object obj) { Console.WriteLine(obj); })

    但编译器的实现会带来一点点overhead,会生成一个小小的静态WaitCallback对象,可以用Reflector看生成的代码。(不要打开Reflector的optimization,否则就看不到了)

    如果是自己写的话,可以选择每次动态建立一个WaitCallback对象然后销毁。当然这样做性能可能差一些,但这里的idea是:编译器会自动做一些事,但不一定是你所希望的。在使用这些高级feature前,最好先搞清楚背后发生了什么。

    另一个细节:如果匿名函数中使用了外层函数的局部变量(即所谓的function closure),会导致创建额外的shared-state object,把用到的局部变量做成一个新对象传给匿名函数。

    上述描述同样适用于lambda函数。因为C#的lambda函数就是匿名函数,改了改语法而已。

  10. Nullable type

    虽然C#要求value type的值不能是null,但写数据库程序时经常遇到某个值是null的情况。为此,C#2.0引入了Nullable type。例如,int? x = null。

    int? x其实就是一个缩写,等价于Nullable<int> x。Nullable是预定义的一个类,简单地对x作了封装。(因为增加了一个类,显然对性能稍微有点影响)

    这个小改动的实现其实很麻烦,需要修改CLR。为什么?因为原先的x是一个value type,现在则变成了一个object,看这个:

    void M(Object o) {
      if (o=null) {Bar();}
    }
    void F() {
      int? x = null;
      M(x);
    }

    如果CLR不专门做修正的话,上面的Bar()不会被执行。(思考题:想一想为什么~)

    另外,C#还引入了一个默认值运算符“??”,称为null-coalescing operator。

    一句话,x ?? value是 (x==null) ? value: x的简写。

  11. 属性(property)的简单声明

    public int x {get; private set;}是个很好用的句式。

    注意,public int x {get;}是错误的,不能通过编译。

  12. Extension method

    static class MyExtMethods {
      static public GetFirstLetter(this string s) {return s[0];}
    }

    然后就可以用string s = “hello”; char ch = s.GetFirstLetter()了。

    原理很简单,编译器把上面那句话翻译成MyExtMethods.GetFirstLetter(s)。LINQ就用到了这个技术。

  13. 匿名类型的背后。。。

    var o = new {name = “Xiangpeng”, id = 123 };

    在这背后是编译器生成的一个匿名类,包含了两个只读属性,形如public int id { get {return _id;} }为什么不做成可读写的呢?

    很微妙。匿名类自动生成了GetHashCode(),返回的是对所有属性的hash code做XOR的结果。如果允许修改属性值,那么Hash code的值就会变化;而这个可能会出问题~保险起见,只读吧。

  14. 每个thread占1M物理内存

    在Win32编程中thread的1M stack空间是Reserve的,直到真正用时才占用物理内存;而在.net中,这1M空间直接被commit。

    还好,可以在新建thread时指定stack size。不过这也比较危险,设小了怕不够。实际上,最好尽量避免创建thread——太多的thread要么导致CPU竞争和context switch,要么都block着浪费内存。建议是:能用ThreadPool就用ThreadPool。

累死了,写了这么多……Jeffrey还有一个更牛的课:.net threading。里面的东西更多……要不要再总结一下呢。。。Thinking

28一/090

用c#从Outtlook 2007里读取email信息

首先要添加对Microsoft.Office.Interop.Outlook的引用。

image

using Microsoft.Office.Interop.Outlook之后,操作Outlook的代码如下。

注意,代码中演示了如何取出特定文件夹,和取出inbox等特殊文件夹:

Application myApp = new ApplicationClass();
NameSpace mapiNameSpace = myApp.GetNamespace("MAPI");
MAPIFolder folder;

folder = myApp.Session.Folders["邮箱 - Xiangpeng Zhao"].Folders["Maillists"].Folders["Windows 7"];
//folder = mapiNameSpace.GetDefaultFolder(OlDefaultFolders.olFolderInbox);

foreach (MailItem mail in folder.Items) {
    string subject = mail.Subject;
    string body = mail.Body; // this will trigger the security warning...
    string senderName = mail.SenderName;
    string senderEmail = mail.SenderEmailAddress; // security warning
}

如何跳过讨厌的Outtlook安全警告!

运行上面的代码,Outlook就会弹出一个对话框:“A program is trying to access e-mail address information stored in Outlook…”必须按下“Allow”才能访问email信息。怎么跳过这个对话框?

image

这个问题的解决方法比我想像得复杂。针对不同的场景,可能需要不同的方案。Outlook "Object Model Guard" Security Issues for Developers是一篇非常好的文章,介绍了各种方法。

因为我只想读取我自己机器上的email,所以就装了个免费的Outlook插件Advanced Security for Outlook,它可以自动替换Outlook的安全警告对话框,取而代之的是一个允许自定义信任程序的对话框:

image

这确实很方便。

30十二/082

SQL Server 2008 Reporting Service使用技巧

SSRS用来做报表很方便,据说比Crystal Reports好用。简单的说,你的报表数据来自SQL语句,然后就可以在类似Excel的环境中画图了。

说是这么说,实际做起来还是会遇到很多小麻烦。下面是总结的一些技巧:

  1. 改变图表上字体大小(如X轴、Y轴上的数字):

    先把LabelsAutoFitDisabled属性设为True ,然后再设置字体大小

  2. Data Label显示设置:

    在Series的SmartLabels里面有一些有用的选项。AllowOutsidePlotArea设为True比较好。

  3. 自定义Legend标题:

    要右键选Series的属性,不是Legend的属性

  4. Pie chart显示百分比:

    在Report properties - code中加入如下代码:

    Public Function GetLabel(ByVal currentValue As Integer, ByVal totalValue As Integer) As String

    If currentValue / totalValue < 0 Then '表示百分比小于1的不显示出来

    Return " "

    Else

    Return Format(currentValue / totalValue, "P1")

    End If

    End Function

    然后设置data label表达式:=Code.GetLabel(Count(Fields!IssueID.Value), Count(Fields!IssueID.Value, "Issues"))

  5. Pie chart排序

    右键点一个Category,在Category Group Properties中设置Sort表达式即可

    clip_image001

  6. 在Pie chart饼图外侧显示DataLabel:

    设置Series的CustomAttributes,PieLabelStyle=Outside

    clip_image002

    注意:参考AdventureWorks示例,有一个很好的饼图。(google上搜到的都是过时的东西)

  7. Asp.net中使用ReportViewer控件:

    必须在IIS的Handler Mappings中新建一个Managed Handler才能正常显示。 可以google搜索Reserved.ReportViewerWebControl.axd。

    clip_image003

    clip_image004

    另一个解决方法:据说配置下web.config文件也可以搞定:

    <httpHandlers>

        <add path="Reserved.ReportViewerWebControl.axd" verb="*"

             type="Microsoft.Reporting.WebForms.HttpHandler,

                   Microsoft.ReportViewer.WebForms,

                   Version=8.0.0.0, Culture=neutral,

                   PublicKeyToken=?????????????"

             validate="false" />

    </httpHandlers>

    http://www.knowsky.com/340782.html

  8. ReportViewer控件:

    可以设置ZoomMode属性为PageWidth,这样可以自动放缩。

    图表放大时会失真,因为不是矢量图。建议把原始报表拉大一些,在页面中留一个小点的空,默认ZoomMode=PageWidth,用户选择100%就可以放大。

    所有的toolbar按钮都可以选择显示或关闭,设置ShowXXX属性即可。

  9. 其他:

    对报表修改之后要及时Deploy,才能看到效果。可以在VS的configuration manager里面设置,debug时自动deploy,比较方便。这个默认是没有打开的,如下图所示,建议把Deploy的对勾打上。

    clip_image005

标签: 2 评论
21十二/080

LINQ学习笔记

什么是LINQ

LINQ是C# 3.0的新功能,可以用统一的的语法(类似sql、或者是函数式语言)访问各种数据,包括数据库、XML、对象。

Anders Hejlsberg说LINQ是"It's about turning query set operations and transforms into first-class concepts of the language" (http://channel9.msdn.com/showpost.aspx?postid=114680)。我的感受是:LINQ可以取代SQL,成为一种统一Database、XML世界的查询语言。

举个例子:

var bycity = from p in db.Products
             join o in db.Orders
             on p.productID equals o.productID
             where o.ShipToCity == "Beijing"
             select new {o.orderID, p.productName};
foreach (d in bycity) ...
//或者GridView1.DataSource = bycity

这里的db.doctors可以是数据库DataSet,可以是个xml文件,也可以是个List<T>。

所有的新关键字,比如var, from, group, select...都是syntactic sugar。编译器会自动把它翻译成基于Lambda表达式的代码,最后翻译成.net 2.0的程序。var的类型是type inference推断出来的,是强类型的,不等于object;select相当于函数式语言中的Map,当然也支持函数式语言中的Reduce(叫做Aggregate);函数式语言用到的Lambda表达式其实很容易用函数指针delegate实现;最后生成的是一个匿名类型(anonymous type)。

推荐这本小书:LINQ: The Future of Data Access in C# 3.0,只要两小时就看完了。了解一点原理后再用LINQ就方便多了。

LINQ和ASP.net

对ASP.net程序员而言,LINQ主要的应用是用它代替SQL访问数据库。除了不用拼字符串了,一个好处是,LINQ是强类型的,所以用起来更安全。我可以这样写:

var query = db.Orders.Where(o=>o.Description.Contains(txtDescription.Text));
// Contains会被翻译成SQL的LIKE
DateTime sinceDate = DateTime.Parse(txtSinceDate.Text);
query = query.Where(o=>o.ShipDate > date);
// o.ShipDate也是DateTime类型的,所以可以直接比较

Lambda表达式很好用的。
比较麻烦的是,现在有两套数据库访问框架:一个是LINQ to SQL,一个是LINQ to Entity。在用LINQ前,又要花点时间考虑用哪个框架好。

二者对于各种基本CRUD操作有很好的支持。LINQ to SQL可以理解为SQL的替代品,基本上跟SQL能一一对应起来;而LINQ to Entity是2008年8月才推出的,是一个更强大的ORM框架,对多对多关系的支持更好。

举个例子:假设一个表linkProductOrder里只有两列,productID和orderID,用于表达product和order的联系。在LINQ to SQL中这个表会被映射到一个类linkProductOrder,还需要自己写join;而LINQ to Entity中就不会出现这个类,直接用product.Orders和order.Products就可以实现互相访问,完全消除了写join的必要。

我的体会是:LINQ to Entity目前还不够稳定,还是LINQ to SQL保险。用ORM框架的一个问题是,刚开始用时会有lose control的感觉,出了问题完全不知道怎么回事,不像SQL,模型很简单清晰,一个query下去肯定不会出毛病。

我用LINQ to Entity时遇到了几个问题,比如数据库改变后没法重新刷新对象模型,只能删掉对象模型文件重建;还有一次不知道为何新建的对象存不进数据库,这时调试起来非常麻烦。对于复杂的含有多个join的查询,我一般都会先用sql server测试一下,再写成代码;LINQ to Entity不用写join是省了一点事,但是这样反而要在脑子里维护两种模型翻过来译过去。相比之下LINQ to SQL就没出过什么问题。

希望等LINQ to Entity的下个版本出来之后,这种问题会少一些。

总结:不是做广告,C#真的很好很强大。

9十一/080

微软PDC大会和Channel 9

微软PDC大会展示了微软最新的技术,比如Windows 7,Windows Azure,而且门票可是超级贵的。最近才知道PDC的全部视频都是可以随便观看和下载的,就在微软MSDN的channel 9上。

MSDN上有很多东西——一个缺点就是太多。Channel 9是developer的频道,有很多视频,比如对Mark Russinovich的采访,讲到了Windows 7 kernel的一些改进。比如内核几个频繁使用的全局lock被细化,提高了多CPU时的performance; 启动时并行装载驱动程序,提高了boot performance;等等。虽然没有字幕,不过总的来说还算好懂。

最后很土的说,我真的没想到微软technical fellow(请对比IEEE fellow,ACM fellow的概念),sysinternal的创始人,在加入微软前凭着debugger就写出Windows Internals一书的Mark大神竟然那么年轻那么帅……在镜头面前甚至有一点腼腆……我一直以为他应该是个留着小胡子戴着眼镜老大叔的形象……

8九/082

用VSTO 2008写一个Outlook 2007插件

VSTO是微软的Office开发框架,基于.Net。跟以前的VBA宏相比,功能更强,优点很多,而且可以在Visual Studio里面用。我用VSTO做了一个Outlook插件(Addin),模拟了Gmail的“存档”按钮。

为什么做这个?

我喜欢Gmail的“存档(Archive)”按钮,它的功能很简单,就是把选中的邮件(一般是已经看过的邮件)移动到一个叫“Archive”的文件夹里。这样做的好处是可以保持收件箱(Inbox)里的邮件比较少(留下的都是要用的),看起来比较干净,而且载入的速度也快(以前我的Outlook收件箱里有5000封信,每次打开都很慢)。

虽然Outlook也很强大,虽然我也可以建一个“Archive”文件夹,把看过的email用鼠标拖拽过去,但这其实很麻烦,稍不留神就丢到错误的文件夹里了。所以我就花了些时间做了这个小程序。

实现

1. 首先在VS 2008里建一个Outlook 2007 Addin工程,在ThisAddIn类中加了几个成员变量:

        private Office.CommandBar archiveToolBar;
        private Office.CommandBarButton archiveEmailButton;
        private Outlook.Explorers selectExplorers;
        private Outlook.MAPIFolder inBox;
        private const string ARCHIVE_FOLDER_NAME = "Archived emails";

2. 加一个Toolbar,放一个"Archive"按钮进去。

        private void ThisAddIn_Startup(object sender, System.EventArgs e)
        {
            // Get inbox reference
            inBox = this.Application.ActiveExplorer().Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
            // Add toolbar
            selectExplorers = this.Application.Explorers;
            selectExplorers.NewExplorer += new Outlook
                .ExplorersEvents_NewExplorerEventHandler(newExplorer_Event);
            AddToolbar();
        }
        private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
        {
        }
        private void newExplorer_Event(Outlook.Explorer new_Explorer)
        {
            ((Outlook._Explorer)new_Explorer).Activate();
            archiveToolBar = null;
            AddToolbar();
        }
        private void AddToolbar()
        {
            if (archiveToolBar == null)
            {
                Office.CommandBars cmdBars =
                    this.Application.ActiveExplorer().CommandBars;
                archiveToolBar = cmdBars.Add("Archive Email",
                    Office.MsoBarPosition.msoBarTop, false, true);
            }
            try
            {
                Office.CommandBarButton button_1 =
                    (Office.CommandBarButton)archiveToolBar.Controls
                    .Add(1, missing, missing, missing, missing);
                button_1.Style = Office
                    .MsoButtonStyle.msoButtonCaption;
                button_1.Caption = "Arch&ive";
                button_1.Tag = "Archive selected email";
                if (this.archiveEmailButton == null)
                {
                    this.archiveEmailButton = button_1;
                    archiveEmailButton.Click += new Office.
                        _CommandBarButtonEvents_ClickEventHandler
                        (ArchiveButtonClick);
                }
                archiveToolBar.Visible = true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

3. 响应Button click事件,代码如下:

        private void ArchiveButtonClick(Office.CommandBarButton ctrl, ref bool cancel)
        {
            // Make sure we are at "inBox"
            Outlook.Explorer activeExplorer = this.Application.Explorers.Application.ActiveExplorer();
            if (activeExplorer.CurrentFolder.FullFolderPath != inBox.FullFolderPath)
            {
                MessageBox.Show("Please do archive operation in " + inBox.Name);
                return;
            }
            // Get "archive" folder
            Outlook.MAPIFolder archiveFolder = null;
            try
            {
                archiveFolder = inBox.Folders[ARCHIVE_FOLDER_NAME]; // ARCHIVE_FOLDER_NAME is a const string I defined.
            }
            catch (Exception ex)
            {
                inBox.Folders.Add(ARCHIVE_FOLDER_NAME, missing);  // Create a new folder if not exist.
                archiveFolder = inBox.Folders[ARCHIVE_FOLDER_NAME];
            }
            // move selected items to "archive" folder
            Outlook.Explorer activeExplorer = this.Application.Explorers.Application.ActiveExplorer();
            foreach (object selectedItem in activeExplorer.Selection)
            {
                try
                {
                    Outlook.MailItem moveMail = selectedItem as Outlook.MailItem;
                    if (moveMail != null) // TODO: && movemail is in "inBox"
                    {
                        //string titleSubject = (string)moveMail.Subject;
                        //if (titleSubject.IndexOf("Test") > 0)
                        moveMail.Move(archiveFolder);
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

在自己的机器上编译运行这个小程序后,Outlook就会自动加入这个插件,以后每次启动Outlook都会运行。不过,要想做个安装包在别人机器上运行,可就麻烦了。这里有个“简单”部署教程 Update: VSTO 2008里,部署超级简单!

部署

VSTO 2008新增了ClickOnce功能。 只要右键点项目,选“publish”就可以生成安装文件,超级简单!这篇文章里有几个截图。

总结

VSTO挺好用,什么时候给IE写插件也能用.Net就好了。MS Office在不断进步,Open Office,WPS Office貌似永远都赶不上啊……

资料

VSTO for Mere Mortals,讲VSTO的一本入门书,适合入门,不过不详细。

MSDN里有好多how to小例子,值得看看。

30八/08

如何用Visual Studio 2008和Sql Server 2005 Express写一个数据库程序

装了Vista,SQL Server 2000不能用了。那就用Visual Studio自带的sql server express试试吧。没想到还挺难上手的,配置很麻烦。花了一晚上时间,终于配好了,下面是过程记录。

关键字:教程,配置,例子

一、安装

装完Visual studio和所带的sql server 2005 express之后,还要装如下的东西:

为了便于管理,你还需要去下一个管理器SSMSEE:
http://download.microsoft.com/download/1/1/0/110d908f-c445-4523-b939-220c7d135f3d/SQLServer2005_SSMSEE.msi
(注意:在vista下一定要run as administrator!步骤是,先启动一个admin权限的cmd窗口,再执行.msi程序,否则安装失败)

Northwind数据库示例:(从Sql Server 2005之后,northwind就“消失”了,必须自己下载)
http://www.microsoft.com/downloads/details.aspx?FamilyID=06616212-0356-46A0-8DA2-EEBC53A68034&displaylang=en
安装.msi文件后,到C:\SQL Server 2000 Sample Databases下执行相应脚本即可。

SQL Server 2005 Books Online文档:(153MB)
http://technet.microsoft.com/en-us/sqlserver/bb428874.aspx

测试一下:在vs 2008的cmd prompt下执行sqlcmd命令,启动文本界面。
(注意大小写!-S,不是-s)

D:\Program Files\Microsoft Visual Studio 9.0\VC>sqlcmd -S .\sqlexpress -E
1> use northwind
2> go
Changed database context to 'Northwind'.
1> select * from employees
2> go

最后,修改sql server express的配置:

1、开启sql2005远程连接功能:
配置工具->SQL Server 外围应用配置器->服务和连接的外围应用配置器->打开MSSQLSERVER节点下的Database Engine 节点,先择"远程连接",接下建议选择"同时使用TCP/IP和named pipes",确定后,重启数据库服务.

(不开的话,很可能Visual studio连不上数据库。)

2、登陆改为混合模式:
打开management studio管理器->以windows方式连接并进入数据库->右键点击你的数据服务器->属性->security>选中Sql server and windows Authentication

3、新建Sql server方式的用户名和密码:
management studio管理器->security->右键点击logins->new login...->选中sql server authentication->设置login name 和password(confirm password)
最好去掉“enforce password expiration”前的小钩,否则每次登陆都要修改密码。
/*
management studio管理器->windows Authentication>new query>sp_password null,'sa123456','sa'
这样就设置了一个用户名为sa ,密码为:sa123456的用户,下次在登陆时,可以用Sql server方式,
用户名为sa ,密码为:sa123456的用户进数据库了.
*/

4、做完上面三步后,这样写连接字符串就可以顺利进入数据库了(server=.\\sqlexpress;uid=用户名;pwd=密码;database=master")。

5、在configuration manager中打开sql server browser服务。否则visual studio无法自动发现数据库名。

注意,server不能写=local!必须用“.”

二、写一个数据库程序:

1、在visual studio中Add connection,有两种方式:

* 文件方式
可以选Sql server database file,然后在
C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Data下面打开northwind.mdf
(注意:vista中,要以admin身份运行visual studio!否则没有权限打开数据库。)

* 数据库方式
用sql server的标准data source模式连接数据库,一开始不知道为啥总是看不到数据库列表。后来发现:必须打开sql server browser服务。该服务默认是关闭的。

2、写程序

最简单的方法,只要把某个data table拖到form上松开就可以了,VS会自动帮你配好datasource, dataset, tableadapter等一大堆控件。参考这个视频教程(MSDN上有很多类似的视频小教程,很不错)。

或者参考Visual Studio自带的例子程序,在\Program Files\Microsoft Visual Studio 9.0\Samples\1033目录下,是一个zip文件。(不好找啊!)这里面的例子都非常好。

最后,Beginning C# 2005 Databases:From Novice to Professional 是一本不错的书,特别是前两章。《Beginning C# 2008 Databases》似乎还不如2005讲的好。

14八/080

关于GPU的一些简单概念

最近看了一些Windows graphics的东西,顺便了解了一下GPU,学了几个显卡设置里常见的单词。Windows vista使用的半透明桌面效果,还有Win+Tab的切换效果都是基于显卡3D加速的。

shader: 不太好翻译,程序纹理着色器,或者着色程序,是一段可以改变像素、顶点和几何学特征的小程序。特点是可编程,原先的显卡里只能调用固定的函数。

vertex shader:把3D坐标变成屏幕上2D坐标(和Z-buffer)

geometry shader:不清楚,一次处理一批vertex?(DirectX 10加入)

rasterization:光栅化,把一个2D坐标换算成一个pixel

pixel shader:对像素上色,考虑texture、光线等因素。(高度并行化,因为每个pixel都是独立的)

unified shader:有利于平衡使用。一个GPU可能有128个处理器,有了unified shader后,某个时刻可以让90%的处理器做vertex shader,10%的做pixel shader;或者反之。(DirectX 10加入)

工作流程:

figure 3 image

因为shader是可编程的,所以可以把某些CPU的计算交给GPU做,也就是所谓的general purpose GPU,这是比较时髦的技术了。

现在的GPU里有很多的处理器,也有调度器,有优先级的概念。但是还不支持page table,因此显存里放的东西都是连续的(这意味着显存里可能会有洞,浪费空间);也不支持抢占。可以预计将来的GPU还会有更多改进。

参考文章:

http://diy.pconline.com.cn/graphics/reviews/0708/1076067_1.html

http://en.wikipedia.org/wiki/Shader

 How GPUs work, IEEE Computer