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……郁闷,还是不清楚。这也意味着即使我通过别的方法把它搞清楚,也不能把结果贴出来了。
C#和CLR的15个细节
这两周一直在training,一共听了4个课程,相当的累啊。
今天先把Jeffrey Richter的培训课:C# and CLR中讲到的一些东西整理一下:
- foreach的性能问题
foreach(string s in rows) { foo(s); }的实现是:
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。值得注意。
- 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的函数都会被编译器做成一个状态机。每调一次,就接着上次的状态继续运行。简单有效啊。我一直以为要有什么特殊的办法呢。
- exception handling的实现决定了throw的performance较差。
可以用Int32.TryParse代替try{Int32.Parse…}catch{…},稍快一点。类似地建议使用Dictionary.TryGetValue。
- .Net CLR执行引擎对应于MSCorWks.dll和MSCorEE.dll这两个文件。
- .Net 3.0, 3.5没有对CLR作任何修改。
所有增加的东西(比如LINQ)都是syntactic sugar,只改了C#编译器而已。
- 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里,以实现动态装卸。
- 动态载入Assembly的陷阱
Sytem.Reflection.Assembly.LoadFrom(pathName)并不会载入pathName所指定的dll,而是看看pathName那个dll的名字、版本,然后到系统默认位置去找。(陷阱啊)
- C#里用reflection创建一个新对象 用Activator.CreateInstance。(奇怪的名字啊。)
- 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比较?)
- 匿名函数的背后。。。
在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函数就是匿名函数,改了改语法而已。
- 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的简写。
- 属性(property)的简单声明
public int x {get; private set;}是个很好用的句式。
注意,public int x {get;}是错误的,不能通过编译。
- 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就用到了这个技术。
- 匿名类型的背后。。。
var o = new {name = “Xiangpeng”, id = 123 };
在这背后是编译器生成的一个匿名类,包含了两个只读属性,形如public int id { get {return _id;} }为什么不做成可读写的呢?
很微妙。匿名类自动生成了GetHashCode(),返回的是对所有属性的hash code做XOR的结果。如果允许修改属性值,那么Hash code的值就会变化;而这个可能会出问题~保险起见,只读吧。
- 每个thread占1M物理内存
在Win32编程中thread的1M stack空间是Reserve的,直到真正用时才占用物理内存;而在.net中,这1M空间直接被commit。
还好,可以在新建thread时指定stack size。不过这也比较危险,设小了怕不够。实际上,最好尽量避免创建thread——太多的thread要么导致CPU竞争和context switch,要么都block着浪费内存。建议是:能用ThreadPool就用ThreadPool。
累死了,写了这么多……Jeffrey还有一个更牛的课:.net threading。里面的东西更多……要不要再总结一下呢。。。![]()
用c#从Outtlook 2007里读取email信息
首先要添加对Microsoft.Office.Interop.Outlook的引用。
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信息。怎么跳过这个对话框?
这个问题的解决方法比我想像得复杂。针对不同的场景,可能需要不同的方案。Outlook "Object Model Guard" Security Issues for Developers是一篇非常好的文章,介绍了各种方法。
因为我只想读取我自己机器上的email,所以就装了个免费的Outlook插件Advanced Security for Outlook,它可以自动替换Outlook的安全警告对话框,取而代之的是一个允许自定义信任程序的对话框:
这确实很方便。
SQL Server 2008 Reporting Service使用技巧
SSRS用来做报表很方便,据说比Crystal Reports好用。简单的说,你的报表数据来自SQL语句,然后就可以在类似Excel的环境中画图了。
说是这么说,实际做起来还是会遇到很多小麻烦。下面是总结的一些技巧:
-
改变图表上字体大小(如X轴、Y轴上的数字):
先把LabelsAutoFitDisabled属性设为True ,然后再设置字体大小
-
Data Label显示设置:
在Series的SmartLabels里面有一些有用的选项。AllowOutsidePlotArea设为True比较好。
-
自定义Legend标题:
要右键选Series的属性,不是Legend的属性
-
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"))
-
Pie chart排序
右键点一个Category,在Category Group Properties中设置Sort表达式即可
-
在Pie chart饼图外侧显示DataLabel:
设置Series的CustomAttributes,PieLabelStyle=Outside
注意:参考AdventureWorks示例,有一个很好的饼图。(google上搜到的都是过时的东西)
-
Asp.net中使用ReportViewer控件:
必须在IIS的Handler Mappings中新建一个Managed Handler才能正常显示。 可以google搜索Reserved.ReportViewerWebControl.axd。
另一个解决方法:据说配置下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>
-
ReportViewer控件:
可以设置ZoomMode属性为PageWidth,这样可以自动放缩。
图表放大时会失真,因为不是矢量图。建议把原始报表拉大一些,在页面中留一个小点的空,默认ZoomMode=PageWidth,用户选择100%就可以放大。
所有的toolbar按钮都可以选择显示或关闭,设置ShowXXX属性即可。
-
其他:
对报表修改之后要及时Deploy,才能看到效果。可以在VS的configuration manager里面设置,debug时自动deploy,比较方便。这个默认是没有打开的,如下图所示,建议把Deploy的对勾打上。
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#真的很好很强大。
微软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大神竟然那么年轻那么帅……在镜头面前甚至有一点腼腆……我一直以为他应该是个留着小胡子戴着眼镜老大叔的形象……
用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小例子,值得看看。
如何用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讲的好。
关于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加入)
工作流程:

因为shader是可编程的,所以可以把某些CPU的计算交给GPU做,也就是所谓的general purpose GPU,这是比较时髦的技术了。
现在的GPU里有很多的处理器,也有调度器,有优先级的概念。但是还不支持page table,因此显存里放的东西都是连续的(这意味着显存里可能会有洞,浪费空间);也不支持抢占。可以预计将来的GPU还会有更多改进。
参考文章:
http://diy.pconline.com.cn/graphics/reviews/0708/1076067_1.html