只是一个简单的测试, 用了三种方法来做10万条记录的插入.  不过我没有测试拼10万条sql插入的效率.
应用在:dell inspiron 640M本本上跑的. 1.60双核CPU, 2G内存.  服务器是HP360, 8CPU, 4G内存. SQL2000数据库.
仅供参考.

一.每次都调用ctx的InsertOnSubmit方法把对象放入:
2008-7-18 14:29:55 开始生成100000个对象. 并直接放入ctx; 用时4秒
2008-7-18 14:29:59  开始SubmitChanges;                   用时3分26秒
2008-7-18 14:33:25  完成.

运行时内存占用了4M左右.

二. 先生成一个list, 最后把list调用ctx的InsertAllOnSubmit方法把全部对象放入:
2008-7-18 18:45:06 开始生成100000个对象. 并放入list 用时1秒
2008-7-18 18:45:07 开始把list全部对象加入ctx.  用时2秒
2008-7-18 18:45:09 开始执行submitChange  用时3分33秒. 应该是数据库的原因导致的慢了7秒. 个人认为不重要.
2008-7-18 18:48:42 完成.

运行时内存占用了4M左右.

三.每生成一个记录都调用ctx的insertOnSubmit, 并且都立即执行submitChanges. 每5000个报一次.
2008-7-18 19:41:28
2008-7-18 19:41:29 0
2008-7-18 19:42:08 5000    此5000条用 39 秒
2008-7-18 19:43:39 10000   此5000条用 91 秒 多了52
2008-7-18 19:46:02 15000   此5000条用143 秒 多了52
2008-7-18 19:49:17 20000   此5000条用195 秒 多了52
2008-7-18 19:53:25 25000   此5000条用248 秒 多了53
2008-7-18 19:58:29 30000   此5000条用304 秒 多了56
2008-7-18 20:04:28 35000   此5000条用359 秒 多了55
2008-7-18 20:11:22 40000   此5000条用414 秒 多了55
2008-7-18 20:19:14 45000   此5000条用472 秒 多了58
2008-7-18 20:28:05 50000   此5000条用531 秒 多了59
2008-7-18 20:37:50 55000   此5000条用585 秒 多了54
2008-7-18 20:48:35 60000   此5000条用645 秒 多了60
2008-7-18 21:00:38 65000   此5000条用723 秒 多了78
2008-7-18 21:13:01 70000   此5000条用743 秒 多了20
2008-7-18 21:26:01 75000   此5000条用780 秒 多了37
.... 等不及了, 关了程序了.                
运行时内存占用了4M左右.

越来越慢.

posted @ 2008-07-18 21:54 HAL9000 阅读(1449) | 评论 (27)编辑
     摘要: 多年了,没有什么技术再能让我激动得无法控制住自己,包括WPF的超炫界面功能,我也只是小小地喜悦了一下,但毕竟知道界面设计更多还是美工创意的功夫,见过很多品味不够的开发人员,把自己程序界面搞得花里胡骚,简直得像不小心坐在调色板上的大熊的屁股,只能让人笑话。所以WPF的UI能力似乎离自己还有距离。
  但是,Linq,却真得把我雷到了。在我重新坐下来写这段话之前,我是激动得在屋里转了几圈的,嘴里至少把MS骂了十来句“WC!”,这骂不是怀了恨意的骂,而是怀了敬意的骂,是没办法控制自己兴奋和激动的心情的骂,就像是《朱罗纪公园》里的马尔康姆教授第一眼看到人工DNA造出来的活恐龙时,说的那句话:“这帮狗娘养的真的做了!”
  阅读全文
posted @ 2008-07-17 23:04 HAL9000 阅读(2538) | 评论 (71)编辑

在MSDN上闲逛, 无意中看到一个这样的东西: 屏幕逻辑集成.

 SLI(屏幕逻辑集成,Screen Logic Integration)用于将古老的UNIX绿色终端字符界面的程序包装成为一个web services, 以便在SOA的架构里重用这些古老的业务逻辑. 

比如, 在我们公司中, 业务系统是基于UNIX的终端程序,  一些业务逻辑是在界面上的一些输入框里输入参数, 一些资料, 或是计算结果被显示在屏幕上的一个地方, 这些业务逻辑通过NEON Systems ServiceBuilder可以以web services的方式发布. 其过程如下:

    1.在VS中新建一个NEON Systems ServiceBuilder的项目以建立一个SLI方案.(当然, 前提是你得先安装了这个东西).
    2.向导提供一个录制器, 用来记录你的telnet程序的输入和输出, 记录下屏幕上的所有的输入了信息的地方和输出了信息的地方.
    3.你在向导的录制结果中, 以直观的方式指定哪些是输入参数, 那些区域是输出结果. 还有数据类型等.
    4.向导生成有关的对象模型, 生成webservice.
  
    实际运行时呢? 我猜是这样的:
    1. web services被调用, 参数被传入. webservices程序调用neon的程序.
    2. NEON偷偷以telnet协议连入unix主机, 按录下的按键序列调用unix主机上的程序.
    3. 参数在指定的地方由程序摸拟输入.
    4. 主机程序回应结果, 这些结果本来是要显示在屏幕上的, 现在被NEON得到, 根据指定的位置信息和这些信息对应, 分辩出哪些是什么字段, 返回给web services程序.
    5. web services向调用者回应结果对象.

    这个东西真得有用. :D

MSDN上的文章在这里:
http://www.microsoft.com/china/MSDN/library/KnowledgeBase/kb_0409.aspx

posted @ 2005-11-14 11:30 HAL9000 阅读(718) | 评论 (1)编辑

 

项目组的文档风格问题

 

  叫我怎么说?我们项目组里现在充斥着华而不实的文档作风. 做一件事,这样浮燥,这样不脚踏实地是不行的.

 

  写工作文档,规范严格是重要的,但并不是要把简单问题往复杂了搞,不是要把实际问题抽象化,不是要去找一些意义含糊的词语来表达,不是要把一句话可以说明白的意思用一大段话来说得人人都看不懂!

 

  说到工作文档,我想有下面几点要做好,就够了.

  一.句法不能出问题:

  • 主谓宾一个也不能少.
  • 如果主谓宾的词语不能确切地,无岐义地表达事实,那么必须用确切的定语\状语\补语成分.
  • 不推荐应用定状补定子句.如果需要的定状补成分是一个子句,那么尽可能分句,在另一句中对于需要限制定的语素进行详细说明.
  • 标点符号不能出错,括号内外的标点要遵守括号标点的惯例.

 

  二.用词:

  用词的原则为:

  • 能简单不复杂.
  • 能用常用字词表达,则不用冷僻词.
  • 能用有确切含义的技术名词,则不用俗称或是其他非技术名词.
  • 能具体不抽象.例如要传达"椅子"的概念,就用"椅子"这个词,而不是采用"泛化单式坐恣人体支撑家俱"这样的词,虽然然这样说起来显得很高档.
  • 英文缩写词提供术语解释.
  • 有数值指标的,则不用比较级形容词,如"数据库的容量要达到非常大的容量,在大容量下的性能要在可容忍的限度内."这样的话实际上没有传达信息.而"数据库设计要支持1亿条记录的容量,同在达到1亿条数据时,用身份证号查询记录时,得到结果的时间最长不能大于0.1秒"这样的话就精确定义了信息.

看来我们项目组里有些人需要的不是专业技能, 而是需要补习语文!

 

posted @ 2005-09-16 11:49 HAL9000 阅读(621) | 评论 (14)编辑

求助: VC++ 中 DLL编译时结构体成员对齐的问题

现在我们有一个需求, 要求我们用VC++编写一个DLL, 叫GT2MQ.dll, 输出一些函数供一种叫GRAPHTALK(GT)的语言使用, 在这些函数的实现里调用了另一个其他厂商提供的中件间产品的DLL函数(adapter.dll).

GT对DLL函数的调用是有要求的, 其中最重要的是必须在编译时指定结构成员按1字节对齐, 否则GT在调用这个DLL的函数时会出现非法操作.

在GT2MQ里的方法调用adapter.dll的一个方法时, 需要传入一个结构体的指针做为参数, 这个结构体的定定义如下:
/*消息结构*/
typedef struct BusMessage
{
 char messageId[50];
 char correlId[50];
 char appMessageId[30];
 char version[30];
 char bodyType[20];
 char bodyCategory[20];
 char timeStampCreated[30];
 char timeStampExpired[30];
 char srcLogicalId[30];
 char dstLogicalId[30];
 char authenticationId[30];
 char commandMode[30];
 char txnScope[30];
 char *standardBody;
 char *body;
 char priority[20];
 char persistence[10];
 char expiry[10];
 char traceLevel[10];
 char publish[10];
 char backup[10];
 char messageName[384];
 char encoding[30];
 char msgCharset[30];

 long msglen;/*发送消息的长度*/
 long rcvlen;/*接收消息需要的内存*/
 
}BusMessage, *ptrBusMessage;

当我们的DLL函数新建了这个结构体, 清零, 并填写了必要的字段后, 把结构的指针做为参数调用adapter.dll中的一个函数, 然而这时后发现无论如何, 这个方法调用都不成功. 返回的错误是说msglen的字段没有填值. 但那个字段明明是填入了值的.

由于adapter.dll没有源码, 只好通过汇编代码来debug, 才发现这个结构体在我们的dll里和在adapter.dll里对字段寻址时地址不一样, 我们的DLL对msglen的寻址是msg+932, 而adapter.dll对同一个字段的寻址是msg+936!

通过手工计算, 确定msglen成员的偏移值应取932, 但是如是果同一个结构体定义放在一个新建的win32工程中时, 查看汇编代码, 就发现是按936寻址的.

后来再进一步查找, 发现问题出在下面两个字段的定址上:standardBody和msglen, 这两个字段在定址时都向后移动了两个字节, 造成了一共四个字节的偏移, 这使得成员访问数据时出错.

我们怀疑是由于我们的GT2MQ.dll项目里的那个结构成员对齐选项设为"1字节对齐"(/Zp1)造成的, 但是无论我们把这个参数设为多少, 都不会消除这个问题:我们的DLL始终不会为那两个字段增加两个字节的偏移. 何况我们项目的要求是GT2MQ.dll必须指定/Zp1选项, 即使这样解决了也无法满足要求.

我们目前的解决办法是: 在结构体里在standardBody和msglen之前各增加了一个字段: char Reserved1[2]和char Reserved2[2]来强迫我们的DLL为之后的成员定址时加一. 但是感觉这样做并不是很妥当, 必竟我们修改了厂商提供的头文件, 而同一头文件在其他项目里是不会出现问题的.

诚求更好的解决方案, 或是知道如何调整项目设置的高手请赐教!

posted @ 2005-09-05 10:02 HAL9000 阅读(1214) | 评论 (5)编辑
一定得选最时摩的外国系统.
雇法国公司?
搞就搞最 high level 的方法论.
IAA模型直接用上.
SOW最少也得整上三四百页.
什么再保呀,精算呀,两核呀, 银保呀.
能整的全给他划进scope里去.
这边搞个技术组, 那边来个业务组.
办公室门口站一白人经理.
打领带, 笑容特虚伪的那种.
打工的一进门, 甭管是写程序的还是搞需求的都得跟经理打招呼:
morning, 我的output昨天已经加班derived了.
打心里头没底的腔儿.
倍儿没面子.
项目组里再设个资深专家团.
方法论用RUP的.
一天光workshop就是十多个小时.
再请一个美国IBM的顾问,
每天就来工作一个小时.
就是一个字儿----贵.
光确定一个项目组人员结构就要好几十万的.
周围其他项目组不是迭代式实施就是敏捷式开发.
你要是一张口只会讲OOAD呀.
你都不好意思和人家打招呼!
你说这样的项目, 得多少时间上线?
我觉得怎么着也得大后年吧!
大后年? 那只够完成需求分析的.
DAY1定在奥运会后!
你别嫌慢, 这已经是简化的process了.
你得研究甲方的心理.
肯出几个亿做project的,
在乎的就是过程.
这什么叫样板工程? 你知道吗?
样板工程就是不管搞什么project,
都用最考究的方法, 不用最直接的方法.
所以, 我们做IT项目的口号就是
不求能出活, 但求最规范.
posted @ 2005-08-31 15:07 HAL9000 阅读(518) | 评论 (1)编辑
     摘要: 1.1. Windows界面设计标准1.1.1. 易用性l 界面元素的名称、标签应该易懂,用词准确,避免使用模楞两可的字眼,要与同一界面上的其他元素易于区分,能望文知意最好。理想的情况是用户不用查阅帮助就能知道该界面的功能并进行相关的正确操作作。 l disable而不是not visible。l 完成相同或相近功能的按钮用GoupBox框起来,常用按钮要支持快捷方式。 l 完成同一功能或任务的元... 阅读全文
posted @ 2005-07-28 14:25 HAL9000 阅读(1833) | 评论 (2)编辑

经过无数次的重装, 删除, 终于明白了, 必须要先装informix cli 2.82(这是唯一一个可以和oracle 9.2i共存的informix cli 32 版本), 再装oracle 9.2i cli, 才可以同时访问两种数据库的odbc 或oledb的连接, 不然的话就会在新建oracle92的 ODBC或是OLEDB连接时出现找不到oracle驱动程序的问题.

切记切记!

posted @ 2005-06-21 19:37 HAL9000 阅读(697) | 评论 (0)编辑

同一个输出流, 不可以在多线程上共用. 如果要共用, 一定要使用临界段.
不同的输出流, 在多线程上并发处理时互相没有影响.
代码说话:

public static void testmulttts()
{
    Thread [] arT 
= new Thread[8];
    
for (int i = 0; i < arT.Length; i ++)
    {
        arT[i] 
= new Thread(new ThreadStart(testtts));
    }

    
foreach(Thread t in arT)
    {
        t.Start();
        Thread.Sleep(
500);
        System.Console.WriteLine(
"线程已经启动!");
    }            
}


public static void testtts()
{

    
///http://msdn.microsoft.com/library/default.asp?url=/library/en-us/SAPI51sr/html/ispvoice_speak.asp
    SpeechLib.SpVoiceClass sp = new SpeechLib.SpVoiceClass();            

    SpeechLib.SpFileStreamClass fs 
= new SpeechLib.SpFileStreamClass();            
    fs.Format.Type 
= SpeechLib.SpeechAudioFormatType.SAFT8kHz8BitMono;
    fs.Open(
"c:\\" + Guid.NewGuid().ToString() + ".wav" , SpeechLib.SpeechStreamFileMode.SSFMCreateForWrite, false);
    
// sp.AudioOutputStream = fs;
    
// The format of selection criteria is 
    
//"Attribute = Value" and "Attribute != Value." 
    
// Voice attributes include 
    
//"Gender," "Age," "Name," "Language," and "Vendor."
    
// 上述这些属性的值可以从注册表的
    
//HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\MSSimplifiedChineseVoice\Attributes
    
// 看到
    SpeechLib.ISpeechObjectTokens sps = sp.GetVoices("Language = 409""");
    
for (int i = 0; i < sps.Count; i ++)
    {
        sp.Voice 
= sps.Item(i);

        
lock(typeof(Class1))
        {
            sp.Speak(
"speak in English."
                SpeechLib.SpeechVoiceSpeakFlags.SVSFDefault);
        }
    }
    sps 
= sp.GetVoices("Language = 804""");
    
if (sps.Count > 0)
    {
        sp.Voice 
= sps.Item(0);
        
lock(typeof(Class1))
        {
            sp.Speak(
"中华人民共和国, 中央人民政府, 成立了!"
                SpeechLib.SpeechVoiceSpeakFlags.SVSFDefault);
        }
    }
    fs.Close();
    Marshal.ReleaseComObject(sp);
    Console.WriteLine(
"线程录音完成.");
}
}
posted @ 2005-06-05 15:40 HAL9000 阅读(893) | 评论 (1)编辑

先决条件:

装了office2000或更新版本中带的MS语音输入法. 这可能就是MS中国研究院的成果之一. 有语音输入功能和语音拼读功能.

下载ms speech api sdk 5.0或5.1, 如果只用C#开发, 则不用装这个, 如果希望用C++开发, 加装语音库之类的, 不妨也装这个好了. 装了这个, 第一条的也就包含了.

C#工程里加上对com对象"Microsoft Speech API 5.0"的引用. Interop而已.

不再多说, 只贴个代码, 以备日后参考:

public static void testtts()
{
    
//参考文档的起始链接在:
    
//http://msdn.microsoft.com/library/default.asp?url=/library/en-us/SAPI51sr/html/ispvoice_speak.asp

    
// 引擎COM对象.
    SpeechLib.SpVoiceClass sp = new SpeechLib.SpVoiceClass();            
    
    
// 朗读的内容到一个文件流里去.
    SpeechLib.SpFileStreamClass fs = new SpeechLib.SpFileStreamClass();
    
//设定流的格式, 48kHZ, 16Bit, 立体声. 如果是电话音质, 8K8bit单声道就可以了.
    fs.Format.Type = SpeechLib.SpeechAudioFormatType.SAFT48kHz16BitStereo;
    fs.Open(
"c:\\test.wav", SpeechLib.SpeechStreamFileMode.SSFMCreateForWrite, false);
    sp.AudioOutputStream 
= fs;    // 如果不指定这个内容, 那就会在计算机的声卡上放出来.
    
// The format of selection criteria is 
    
//"Attribute = Value" and "Attribute != Value." 
    
// Voice attributes include 
    
//"Gender," "Age," "Name," "Language," and "Vendor."
    
// 上述这些属性的值可以从注册表的
    
//HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\MSSimplifiedChineseVoice\Attributes
    
// 看到

    
// 得到属性符合指定要求的所有的拼读token. "Language = 409"表示得到所有的英文拼读器. 等号两边的空格不可少! 
    // 如果有多个过滤条件要指定, 中间用分号分开, 如要指定英文女声, 则为
    // "Language = 409; Gender = Female"
    SpeechLib.ISpeechObjectTokens sps = sp.GetVoices("Language = 409""");
    
// 可能有多个拼读器. 咱们每个都用一遍,  是不同的嗓音, 有男有女.
    for (int i = 0; i < sps.Count; i ++)
    {
        sp.Voice 
= sps.Item(i);    //这里这个圆括号不是我写错了, 就是这样的.这是一个方法,不是索引器.

        sp.Speak(
"User experience and interface design in the context of creating software represents an approach that puts the user, rather than the system, at the center of the process."
            SpeechLib.SpeechVoiceSpeakFlags.SVSFDefault);
        
// 可以用标志位指定异步调用这个方法. 
    }

    
// 得到中文拼读器, 因为目前只有一个, 也就不用for了.
    sps = sp.GetVoices("Language = 804""");
    
if (sps.Count > 0)
    {
        sp.Voice 
= sps.Item(0);
        sp.Speak(
"中华人民共和国, 中央人民政府, 成立了!."
            SpeechLib.SpeechVoiceSpeakFlags.SVSFDefault);
    }
    fs.Close();
    Marshal.ReleaseComObject(sp);
}


posted @ 2005-06-04 22:56 HAL9000 阅读(2364) | 评论 (7)编辑
问题一: 自已写到一个类, 其中有一个属性是字串型, 是用来保存一个文件名的,  这个类需要客户在使用时能在PropertyGrid里runtime修改内容, 友好的方式当然是让客户在PropertyGrid里可以有一个"..."的按钮, 点一下之后打开一个openfiledialog, 选择一个文件之后返回, 文件的全路径就放在属性值的框里了. 如何达到这个目的?

比如这个类如下:
public class class1
{
    
public class1()
    
{    
    }

    
    
// 

    
private string _s;
    
public string s
    
{
        
get{return this._s;}
        
set{this._s = value;}
    }

}


这样的话在PropertyGrid里s属性的后面只有一个简简单单的编辑框, 为了使s的编辑区可以出现一个"..." 按钮, 并且可以用文件打开对话框选择文件, 可以使用EditorAttribute属性对这个属性进行标记:

[Editor(
typeof(System.Windows.Forms.Design.FileNameEditor), 
        
typeof(System.Drawing.Design.UITypeEditor))]
public string S
{
    
get{return this._s;}
    
set{this._s = value;}
}

FileNameEditor类提供了一个打开文件的对话框, 以编辑属性值, 这个类派生于UITypeEditor类, UITypeEditor是所有设计时界面的基类.

这样就可以达到有文件对话框的目的了, 但是如果想要指定只选择某一种文件类型, 如"WAV"文件, 那就得派生FileNameEditor, 重写有关的方法.

public class SoundFileEditor:System.Windows.Forms.Design.FileNameEditor
{
    
protected override void InitializeDialog(OpenFileDialog openFileDialog)
    {
        
base.InitializeDialog (openFileDialog);
        
// 在基类初始代完对话框之后, 可以对这个对话框做一些手脚.
        openFileDialog.Filter = "wav and vox file(*.wav, *.vox)|*.wav;*.vox|wav files (*.wav)|*.wav|vox files (*.vox)|*.vox|All files (*.*)|*.*";
    }
}

再把Class1中的S的EditorAttribute改为派生的这个子类, 现在对话框里的文件过滤器改为你想要的了.

你甚至可以从UITypeEditor自己重新派生一个子类出来, 自己写一个能弹出"保存文件"对话框的UI编辑类. 注意在重写UITypeEditor的
public virtual new System.Object EditValue ( System.ComponentModel.ITypeDescriptorContext context , System.IServiceProvider provider , System.Object value )
方法, 注意返回自己需要对象就可以了.

问题二:  如何设定一个类的"默认值编辑器"?
例如: 比如有一个类叫SoundFileName专门用来处理声音文件名, 如果Class1中有一个属性FileName是SoundFileName类型, 这个属性在PropertyGrid里编辑器里默认情况下是没有办法编辑的, 为了让SoundFileName类可以在propertyGrid里可以编辑, 必须对SoundFileName进行属性标志, 指定一个默认的编辑器. 假定我们还是希望通过"打开文件"对话框来指定一个文件的方式生成一个SoundFileName对象, 那么我们可以写一个从UITypeEditor中直接或间接派生的子类, 以完成编辑对象内容的操作.

如下代码所示, 这个专门编辑SoundFileName对象的类叫SoundfileNameEditor, 我们随后实现它, 现在先看SoundFileName的实现. 注意class之前的标记:

[EditorAttribute(typeof(SoundFileNameEitor), 
        
typeof (System.Drawing.Design.UITypeEditor))] 
public class SoundFileName
{
    
private string _filename;    
    
public string FileName
    {
        
get{return _filename;}
    }

    
public SoundFileName(string s)
    {
        
this._filename = s;
    }
}

这里定义了此类的值编辑器为SoundFileNameEditor类, 这个类我们需要从UITypeEditor或是其子类中派生出来, 重写其EditValue方法, 以可以返回一个SoundFileName对象.

为了省事, 我就不再从UITypeEditor派生了, 而是从SoundFileEditor派生, SoundFileEditor已经把文件名过滤器修改了, 但是SoundFileEditor的EditValue返回的是一个字串, 这次只要修改SoundFileEditor的EditValue的值就可以了.

public class SoundFileNameEditor: SoundFileEditor
{
    
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
    {
        SoundFileName sfn 
= value as SoundFileName;
        
        
return new SoundFileName(base.EditValue (context, provider, sfn==null?"":sfn.FileName) as string);
    }
}

注意, 这个EditValue总是会返回一个新的对象, 把从前的对象扔掉, 你可以通过判断value是不是null来决定是否新建一个对象, 还是只是修正一下其中的文件名, 这里不再多说了.

现在你在PropertyGrid里可以编辑SoundFileNmae对象了, 编辑器弹出一个打开文件对话框, 选择了文件之后, 根据文件名建立了一个SoundFileName对象.

最后提示一下, 不知道你注意到了没有, 当选择了文件名建立了一个SoundFileName对象之后, 在编辑框里的内容是"testanything.SoundFileName", 用户看起来不会太高兴, 也不直观, 这个也好办, 你可以重写SoundFileName的ToString()方法来用任何方式显示你想要内容.
posted @ 2005-06-02 17:17 HAL9000 阅读(1620) | 评论 (3)编辑