dotnet程序优化心得(二)

本文通过使用Hashtable替代原始字符串替换方法,显著提升了繁简体中文转换程序的性能,从30万字/秒提升到了500万字/秒。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下面以实际例子具体解释相关技巧。

 (1)缘起

bfax@smth.org发了一个字符串转换程序,引起了热烈讨论。原程序如下:

 1None.gif
 2ExpandedBlockStart.gifContractedBlock.gifFunction B2G()Function B2G(prestr As StringAs String
 3InBlock.gif    Dim i, j As Integer
 4InBlock.gif    Const GB_Lib = "dot.gif"    //几千个字符吧,因为字符串长度限制,原程序是由GB_lib1,GB_lib2dot.gifGB_lib4四个字符串构成的,为了简化问题,只用一个字符串代替。
 5InBlock.gif    Const BIG5_Lib = "dot.gif"    //与GB_Lib中简体字一一对应的繁体字
 6InBlock.gif    
 7InBlock.gif    For i = 1 To prestr.Length
 8InBlock.gif        j= Instr(1, BIG5_Lib1, GetChar(prestr, i)) 
 9InBlock.gif        If j<>0 Then prestr=prestr.Replace(GetChar(BIG5_Lib1,j),GetChar(GB_Lib1,j))
10InBlock.gif        j= Instr(1, BIG5_Lib2, GetChar(prestr, i)) 
11InBlock.gif        If j<>0 Then prestr=prestr.Replace(GetChar(BIG5_Lib2,j),GetChar(GB_Lib2,j))
12InBlock.gif        j= Instr(1, BIG5_Lib3, GetChar(prestr, i)) 
13InBlock.gif        If j<>0 Then prestr=prestr.Replace(GetChar(BIG5_Lib3,j),GetChar(GB_Lib3,j))
14InBlock.gif        j= Instr(1, BIG5_Lib4, GetChar(prestr, i)) 
15InBlock.gif        If j<>0 Then prestr=prestr.Replace(GetChar(BIG5_Lib4,j),GetChar(GB_Lib4,j))
16InBlock.gif    Next
17InBlock.gif    Return prestr
18ExpandedBlockEnd.gifEnd Function


(2) 分析问题

写测试程序测试在我的1.5M迅驰本本测试,替换效率为30万字/s,该程序采用Replace,这样对每一个字符都要扫描GB_Lib字符串中的几千个字符,性能自然上不去。需要寻找更好的数据结构和算法,降低每一个字符串的操作时间。

.net类库里有一个很好的东西可以拿来直接用:Hashtable。也就是说,把每一个简体字作为key,每一个繁体字作为value。这样处理每个字符的时候只需要看它在不在Hashtable的key里面,在的话就找出对应的value替换,否则就不做任何操作。这样做的代价是Hashtable初始化的耗时,不过初始化顶多也就一次嘛。程序如下:

 1None.gifpublic class ConvertDemo
 2ExpandedBlockStart.gifContractedBlock.gifdot.gif{
 3InBlock.gif    private static Hashtable _libTable;
 4InBlock.gif
 5InBlock.gif    static ConvertDemo()
 6ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
 7InBlock.gif        InitHashTable();
 8ExpandedSubBlockEnd.gif    }

 9InBlock.gif
10InBlock.gif    static string GB_lib="dot.gif";
11InBlock.gif
12InBlock.gif    static string BIG5_lib="dot.gif";
13InBlock.gif
14InBlock.gif    private static void InitHashTable()
15ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
16InBlock.gif        _libTable = new Hashtable();
17InBlock.gif        PushIntoHashtable(_libTable,GB_lib,BIG5_lib);
18ExpandedSubBlockEnd.gif    }

19InBlock.gif
20InBlock.gif    private static void PushIntoHashtable(Hashtable t, string g , string b)
21ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
22InBlock.gif        for (int i=0;i<g.Length;i++)
23ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
24InBlock.gif            t.Add(g[i],b[i]);
25ExpandedSubBlockEnd.gif        }

26ExpandedSubBlockEnd.gif    }

27InBlock.gif
28InBlock.gif    private static char ConvertChar(char input)
29ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
30InBlock.gif        if (_libTable.ContainsKey(input)) return (char)_libTable[input];
31InBlock.gif        else return input;
32ExpandedSubBlockEnd.gif    }

33InBlock.gif
34InBlock.gif    public static string ConvertText(string inputString)
35ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
36InBlock.gif        StringBuilder sb = new StringBuilder(inputString);
37InBlock.gif        for (int i=0;i<inputString.Length;i++)
38ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
39InBlock.gif            sb[i] = ConvertChar(inputString[i]);
40ExpandedSubBlockEnd.gif        }

41InBlock.gif        return sb.ToString();
42ExpandedSubBlockEnd.gif    }

43ExpandedBlockEnd.gif}


测试性能,结果为300万字/秒。性能提高了10倍。

(3)用relector看Hashtable源代码,消除无用操作,继续优化

还能不能继续优化呢?ConvertChar (char input)执行次数最多,是对性能最有影响的方法。用reflector反编译Hashtable的get_Item(object key)方法:

 1None.gifpublic virtual object get_Item(object key)
 2ExpandedBlockStart.gifContractedBlock.gifdot.gif{
 3InBlock.gif      uint num1;
 4InBlock.gif      uint num2;
 5InBlock.gif      Hashtable.bucket bucket1;
 6InBlock.gif      if (key == null)
 7ExpandedSubBlockStart.gifContractedSubBlock.gif      dot.gif{
 8InBlock.gif            throw new ArgumentNullException("key", Environment.GetResourceString("ArgumentNull_Key"));
 9ExpandedSubBlockEnd.gif      }

10InBlock.gif      Hashtable.bucket[] bucketArray1 = this.buckets;
11InBlock.gif      uint num3 = this.InitHash(key, bucketArray1.Length, out num1, out num2);
12InBlock.gif      int num4 = 0;
13InBlock.gif      int num5 = (int) (num1 % bucketArray1.Length);
14InBlock.gif      do
15ExpandedSubBlockStart.gifContractedSubBlock.gif      dot.gif{
16InBlock.gif            bucket1 = bucketArray1[num5];
17InBlock.gif            if (bucket1.key == null)
18ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
19InBlock.gif                  return null;
20ExpandedSubBlockEnd.gif            }

21InBlock.gif            if (((bucket1.hash_coll & 0x7fffffff== num3) && this.KeyEquals(key, bucket1.key))
22ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
23InBlock.gif                  return bucket1.val;
24ExpandedSubBlockEnd.gif            }

25InBlock.gif            num5 = (int) ((num5 + num2) % ((ulong) bucketArray1.Length));
26ExpandedSubBlockEnd.gif      }

27InBlock.gif      while ((bucket1.hash_coll < 0&& (++num4 < bucketArray1.Length));
28InBlock.gif      return null;
29ExpandedBlockEnd.gif}


我的天天天天天天天天天天天天天........好长呀,先不管这个。哦,方法并不抛出异常,如果key不存在就直接返回null。这样的话,采用ContainsKey(...)判断key是否存在就是多次一举了。

把ConvertChar (char input)改为:

1None.gifprivate static char ConvertChar(char input)
2ExpandedBlockStart.gifContractedBlock.gifdot.gif{
3InBlock.gifobject temp = _libTable[input];
4InBlock.gifreturn temp == null?input:(char)temp;
5ExpandedBlockEnd.gif}


这样大概能节省一半的操作。

测试结果验证了我这一想法。性能一下提高了40%,达到了500万字/s

注:上面程序有小bug,后来发现的。

转载于:https://www.cnblogs.com/Athrun/archive/2007/07/19/823366.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值