贝网博客

我的分类
流水记事
源码下载
Asp.net
其它
数据库
Javascript
.Net技术
我的相册
友情链接
博客园
CSDN博客
Start0
最新回复
fasdfasdf
[:..
lz这个东西好厉害,我..
哈哈,好照片
不错,以前一直用黄色..
终于找到支持ff的修正..
终于找到支持ff的修正..
新鲜性
看看,试试,好不好使。
好东西一起学习[:img0..
 日志列表    
本站一共有博客83条,当前显示81条
回复:6  发表于:2011-02-22 15:44:51
更新于:2012-11-21 11:22:49
记录了小贝的成长日志,有的还带有各个时期的照片,呵呵
回复:2  发表于:2010-07-10 17:52:18
更新于:2013-05-28 15:47:42

概念相关笔记

这是俺学习正则时的一些正则学习笔记
可能理解会有些不对,谁看到谁提哈,嘿嘿

1、容易混淆的单行模式和多行模式:
单行模式只影响.(小数点)的匹配,关闭单行模式,.匹配换行以外的任意字符;开启单行模式,.匹配任意字符
多行模式只影响^和$的匹配,关闭多行模式,^只能匹配字符串开头,$只能匹配字符串结尾;
        开启多行模式,^匹配字符串开头或行的开头,$匹配字符串结尾或行的结尾
因为正则发展的历史原因,造成这2个概念好像是相反的概念,实际这2个概念是没有任何关系的2个概念

2、全局模式(C#没有,js有):关闭时,只匹配一次;开启时,匹配全部字符串,
在js中,关闭全局模式,等效于C#中的Match方法;开启全局模式,等效于C#中的Matches方法

3、贪婪模式与懒惰模式:举例说明:有字符串:0<div>a1</div>b1<div>c1</div><div>d1</div>9
贪婪模式的正则:<div>.*</div>,只有一个匹配结果:<div>a1</div>b1<div>c1</div><div>d1</div>
懒惰模式的正则:<div>.*?</div>,有3个匹配结果,分别是:<div>a1</div>    <div>c1</div>       <div>d1</div>
注:贪婪模式的原理是匹配优先,而懒惰模式的原理是忽略优先,比如:
字符串 abd
贪婪模式正则:ab?c    在匹配时,会先尝试进行ab匹配,再比对c,不匹配了,进行回溯,进行ac的匹配
懒惰模式正则:ab??c  在匹配时,会先尝试进行ac匹配,不匹配了,进行回溯,进行abc的匹配

4、非回溯匹配(也叫固化分组):(?>):举例说明:字符串:张三是中国人,李四是中国人,王五是韩国人
正则:(.*)中国人,因为正则引擎的贪婪特性,.*第一次扫描时会匹配全部字符串,发现后面没有字符了,不能匹配正则里的“中国人”,于是把.*的匹配往前递推一个,发现“国”也不能匹配正则里的“中国人”,于是再把.*的匹配往前递推,一直推到“张三是中国人,李四是”,此时匹配到了“中国人”,于是.*匹配的结果就是:张三是中国人,李四是  这里说的往前递推就是回溯
把正则改为:(?>.*)中国人  匹配就会失败,因为正则式里指定了.*不允许回溯,所以.*第一次扫描时会匹配全部字符串,再往后扫描时匹配不到,就直接返回了,而不会往前递推。注意:非回溯组也是非捕获组,就是这个括号里的值不会被捕获
之所以有这个非回溯,是因为在正则表达式引擎时,回溯是很耗资源和时间的,要尽量避免回溯,比如:
字符串:<a href="http://www.beinet.cn">这是我的网站</a>,要用正则匹配里面的url和文本,可以用下面2个正则,都可以实现:
<a href="(.+?)">(.+?)</a>
<a href="([^"]+)">([^<]+)</a>
但是第一个正则,在匹配时会有回溯,比如href是懒惰匹配,这个.+?会先匹配h,然后看后面是不是",不是,再递推下一个字符t,一直递推19次
而第二个正则,直接就匹配到"前面,不存在回溯,所以在写正则时,要尽量使用没有回溯,或者回溯少的正则

其它笔记

1、\b:表示单词的起始或结束
\B:表示非单词边界(不在单词的开始或结束)
^:表示字符串的起始位置,指定多行模式时,表示行的起始位置
$:表示字符串的结束位置,指定多行模式时,表示行的结束位置

2、反向引用:\1这样的转义数字,代表前面捕获的内容,如果我们想匹配重复的单词,就可以用这种转义数字
举例:this isa a this this a a file list file filea,我们要找出其中重复的单词,可以用正则:
\b([a-z]+)\b \1\b 来匹配,\1表示第一个括号里的内容,\2表示第2个,如此类推

3、捕获的顺序是按左括号的出现顺序,从1开始顺序递增
注:捕获就是把括号里的内容压入堆栈
例如:([+-])?(\d+(\.\d+)?)(.*)
([+-])为捕获的第一个内容,通常为$1,
      C#中可以用Match.Groups[0].Value来得到捕获的值(在正则中可以用\1反向引用,以下类推)
               也可以用Match.Result("$1")来得到捕获的值
(\d+(\.\d+)?)为捕获的第二个内容,通常为$2
而$2中的(\.\d+)为捕获的第三个内容,通常为$3
最后的(.*)为捕获的第四个内容,通常为$4
注意:如果补获组进行了命名,则未命名的第1个左括号为$1,未命名的第2个左括号为$2,以此类推,直到没有未命名的补获为止,再开始按顺序推算有命名的补获组

4、如果对某个括号里的内容不想进行捕获,可以使用?:
例如:例3修改为:([+-])?(\d+(?:\.\d+)?)(.*)
例3里的$3就变成了(.*),而$4就不存在了
技巧:如果不想加?:,可以在匹配时增加选项:RegexOptions.ExplicitCapture,这个选项只会捕获用(?<name>...)的组,但是如果指定了反射引用时,必须对引用的的捕获显式命名,比如正则:<([^\s]+)></\1>,如果指定RegexOptions.ExplicitCapture时会报错

5、替换时保留匹配内容,例如字符串:http://beinet.cn/
要替换成超链接形式<a href=‘http://beinet.cn/’>beinet.cn</a>,可以用C#语句:
    Regex.Replace(@"http://beinet.cn/", @"(http://(.*)/)", @"<a href='$1'>$2</a>");

    Regex.Replace(@"http://beinet.cn/", @"(?<url>http://(?<host>.*)/)", @"<a href='${url}'>${host}</a>");

6、\s匹配空白字符,包括:空格、Tab、换行、回车,等价于 [\t\r\n ]
  \S匹配上述4个字符以外的其它所有字符

  所以:[\s\S] 就可以匹配任意字符了   

7、\w :匹配包括下划线的任何单词字符,等价于 [A-Za-z0-9_]
\W :匹配任何非单词字符,等价于 [^A-Z a-z 0-9_] 

  所以:[\w\W] 也可以匹配任意字符了   

8、\d :匹配所有数字,一般等价于 [0-9]  注:在C#里,默认情况下也匹配全角的0-9
\D :匹配任何非数字
  所以:[\d\D] 也可以匹配任意字符了   

9、.(句点字符。): 匹配除 \n 以外的任何字符。
注意1:[.\n]并不能匹配任意字符,因为在[ ]里,.只是代表自己,不匹配其它字符
              所以要匹配任意字符,请参考:5,6,7
注意2:如果指定正则选项为Singleline,则此时.匹配任意字符了

10、\nnn:匹配一个3位的8进制Ascii字符,如\103匹配大写C字符
\xnn:匹配一个2位的16进制Ascii字符,如\x43匹配大写C字符
\unnnn:匹配一个4位的16进制Unicode字符
\cV:匹配一个控制字符,如\cV匹配Ctrl-V
注意1:为了跟反向引用区分开,表示8进制字符时,比如\43,请写成\043

11、零宽度断言:有的地方称之为环视,或者预搜索,或声明,就是根据表达式匹配一个位置,而不是匹配字符,举例:
有字符串为:abcdefghijklmnopqrstuvwxyz
正声明?=
(?=opq):匹配n与o中间的位置,此时:mn(?=opq),就可以匹配到mn,而m(?=opq)匹配不到东西
                 (?=opq)op,就可以匹配到op,而(?=opq)p匹配不到东西
    举例:Languages have: Java C#.Net C++ Javascript VB.Net JScript.Net Pascal
                正则:\S+(?=\.Net) 将得到结果:C# VB JScript 

逆向正声明?<=
(?<=opq):匹配q与r中间的位置,此时:pq(?<=opq),就可以匹配到pq,而p(?<=opq)匹配不到东西
                   (?<=opq)rst,就可以匹配到rst,而(?<=opq)st匹配不到东西
注:Javascript不支持逆向正声明
    举例:名单:张三 李四 张建四 王五
                 正则:(?<=张)\S+ 将得到结果:三 建四
负声明?|
(?!opq):匹配所有位置,除了n与o中间的位置,此时:[a-z](?!opq),就可以匹配到除n以外的所有字符,而n(?!opq)匹配不到东西
                   (?!opq)[a-z],就可以匹配到除o以外的所有字符,而(?!opq)o匹配不到东西
    举例:123A 456c 789 111C
                 正则:\d{3}(?![A-Z]) 将得到结果:456 789
逆向负声明?<!
(?<!opq):匹配所有位置,除了q与r中间的位置,此时:[a-z](?<!opq),就可以匹配到除q以外的所有字符,而q(?<!opq)匹配不到东西
                   (?<!opq)[a-z],就可以匹配到除r以外的所有字符,而(?<!opq)r匹配不到东西
注:Javascript不支持逆向负声明
    举例:123A 456C 789 111C
                 正则:(?<!1)\d{2}[A-Z] 将得到结果:56C
综合应用举例:
\b\w+(?=o)o\b:匹配所有以o结尾的单词
Regex.Replace("I have 1234567Yuan", @"(?<=\d)(?=(?:\d{3})+(?!\d))", ","):替换字符串里的数字为科学计数法(即3位数字一个逗号)
上面的是C#,Javascript因为不支持逆向环视,所以要用:'123456'.replace(/(\d)(?=(?:\d{3})+(?!\d))/g, "$1,")

12、决策(也叫平衡组)是正则里的3目运算表达式,形如:(?(exp)yes|no),如果exp成立,就匹配yes,否则匹配no
(?!)表示返回匹配失败,如:(\d)(?(1).|(?!))可以匹配以数字开头的任意2个字符
举例1:
字符串:1a cb 3a 5c 3b 正则:(?(\d)\da|b) 可以匹配到结果:1a b 3a b
需要注意的是yes表达式是\da,如果是正则:(?(\d)a|b) 将只会匹配到:b b,
因为expression成立时,是匹配到这个expression的位置,后面的yes也必须要包含这个expression
当然:(?(\d)\wa|b)的匹配结果也是可以的,因为\w包含了\d
对于字符串a1234,正则(?(?<!a)\d\d|\d)可以匹配到1 和 23
举例2:引用前面的条件
字符串:10-12 z0-az 11-sd  正则:(\d)?(0)-(?(1)\d\d|[a-z][a-z]) 后面的?(1),表示前面的第1 个捕获如果匹配时,用yes匹配,否则用no匹配
这个正则可以匹配到:10-12  0-az
参考:http://blog.csdn.net/lxcnn/article/details/4402808
http://www.cnblogs.com/luckcs/articles/2212996.html
 

13、正则表达式选项,(?i:)指定括号内的匹配忽略大小写,比如正则:(?i:a) 表示匹配a或A,而不管是否指定了RegexOptions.IgnoreCase选项
(?n:):指定只有显式命名或编号的组才进行捕获,类似于RegexOptions.ExplicitCapture
(?x:):消除模式中的非转义空白并启用由 # 标记的注释,类似于RegexOptions.IgnorePatternWhitespace
(?m:):指定使用多行模式,类似于RegexOptions.Multiline
(?s:):指定使用单行模式,类似于RegexOptions.Singleline
注:选项可以叠加,比如:(?is:) 表示单行模式,忽略大小写

14、应用 | 时要注意,正则引擎总是选择第一个选项进行匹配,无法匹配时才考虑第2个选项,然后第3个,比如:
字符串:abcd  正则:a|ab 只匹配到 a       而正则:ab|a 则匹配到 ab

15、Javascript提取匹配中的内容举例,下面是在Html里循环提取超链接的Href和链接文本
var a = /<a\s+[^>]*href="([^"\s]*)"[^>]*>([\s\S]*?)<\/a>/ig;
while(a.test(html)){// 第二个test会从第一个test的lastIndex+1处开始匹配
    alert(RegExp.$1);
    alert(RegExp.$2);
}

正则举例

1、需求:如果小数在2位以内,就保持不变,如果有第3位小数,且第3位小数不是0,那也保留,如果是0就不保留,第3位以后的数字全部替换掉
比如:string str = 1.23=》1.23、1.234=1.234、1.230=》1.23、1.2345678=》1.234
此时,Regex.Replace(str, @"(\.\d\d[1-9]?)\d*", "$1")就可以实现,但是对于1.23和1.234,替换操作浪费了一点时间,因为结果相当于用23替换成23
有效率一点的做法是把正则改成:(\.\d\d(?>[1-9]?))\d+
注意里面的固化分组,如果不使用固化分组的正则:(\.\d\d[1-9]?)\d+ 在匹配1.625时,因为\d+至少要匹配一个数字,而[1-9]?可以不匹配,所以导致回溯,\d+匹配了5,导致替换结果成了1.62,与需求不符,所以这里要用固化分组,避免回溯

2、需求:匹配出字符串里的日期,比如:string str = January 31  我们要得到后面的日期31
一般我们会用正则:(0?[1-9]|[12]\d|3[01])  这个多选组合,0?[1-9]匹配01-09或1-9;[12]\d匹配10-29;3[01]匹配30-31,应该是没错的但是匹配的第一个
结果是3,而不是31      这是因为正则引擎按顺序测试组合,0?[1-9]可以匹配3,所以错误结果出现了
正确的正则应该是把能匹配最短数字的0?[1-9]放到最后,变成:([12]\d|3[01]|0?[1-9])  就OK了
或者使用下列正则之一:
(31|[123]0|[012]?[1-9])               (0[1-9]|[12]\d?|3[01]?|[4-9])

3、需求:匹配双引号和里面的内容,内容里允许出现\" 和\\这样的转义
如果内容不包含引号,那正则就是:"[^"]*"
如果加上允许转义的双引号时,我们先用逆序环视,正则变成:"([^"]|(?<=\\)")*",这个表示式可以匹配 "aa\"bb" 这样的文本,但是对于"aa\\" and "bb",它的匹配结果是错误的,因为它把转义的\\后面的这个斜杠去环视了,所以这个正则不能用
再改用:"(\\.|[^"])*",就是匹配\和一个字符,或非双引号,对于上面的这回可以匹配了,不过,对于没有结束双引号的字符串:"aa\"bb,它又匹配到了"aa\",因为正则引擎的回溯到\"时,[^"]能匹配前面的\,于是就返回了匹配成功
所以最终的正则应该是:"([^"\\]|\\.)*"   或者使用固化分组:"(?>([^"]|\\.)*)"
注:这个正则顺序交换一下,变成:"(\\.|[^"\\])*"  也是可以的,但是这个正则回溯比不交换前多,参见下图

4、需求:替换字符串前后的空白(C#的Trim方法已经可以实现,但是js没有这个功能)
在网上最常见的作法是用正则: (^\s*)|(\s*$)  可以搜索 Javascript trim,得到一大堆的类似结果如下:
String.prototype.trim= function(){return this.replace(/(^\s*)|(\s*$)/g, "");} 
这个当然没有问题,但是这个正则是可以改进的,首先,用\s*,这样也可以匹配空,没有空白的字符串也会进行2次替换,
    而且正则里有2个捕获,而实际上捕获没有使用到,
所以比较好的作法是把*改成+,并去掉括号,用:String.prototype.trim= function(){return this.replace(/^\s+|\s+$/g, "");}
注:虽然这点改进很小,但是如果不是替换成"",那结果就出错了,并且在做任何工作时,都想到这么一点点,那总的提升效率还是很多的

5、需求:匹配HTML标签,允许标签中的属性值包含<或>,例如:<input value="a>bc" type="text">
如果没有后面那个要求,那么匹配HTML标签,就是简单的:<[^>]+>
根据要求,我们可以知道,属性值是包含在单引号或双引号里的,所以可以得到下面正则:
<("[^"]*"|'[^']*'|[^'">])*> 

6、需求:匹配嵌套div标签的最内层,例如:<div><div>2<div>3</div></div>1<div>2<div>3<a>3</a>3</div></div></div>,取出3的div
首先自然是两端的正则:<div[^>]*>.*?</div>,这个得到结果:<div><div>2<div>3</div>
那么要求在中间不能出现<div字样,用(?:(?!<div).)匹配前面不等于<div的任意一个字符,得到最终正则如下:
<div[^>]*>(?:(?!<div).)*?</div> 

7、需求:匹配嵌套div标签的最外层
 div>1<div>2<div>3<div>4</div>5 匹配到<div>4</div>
div>1<div>2<div>3<div>4</div>5</div> 匹配到<div>3<div>4</div>5</div>
div>1<div>2<div>3<div>4</div>5</div>6</div>7</div>8</div> 匹配到<div>2<div>3<div>4</div>5</div>6</div>
首先自然是两端的正则:<div> 和 </div>,
然后(?<o><div>)|(?<-o></div>)表示匹配div和相应的结束div,<o>表示把捕获压入堆栈,<-o>表示取出堆栈,堆栈没有数据就表示匹配失败,第三部分(?:(?!</?div)[\s\S])表示不包含div的任意字符,最后还有一块(?(o)(?!))表示如果堆栈中还有div,匹配失败
最终正则如下:
<div>((?<o><div>)|(?<-o></div>)|(?:(?!</?div)[\s\S]))*(?(o)(?!))</div>

8、需求:匹配有效的物理路径,如 c:\ d:/abc/ddd.txt e:\\\\abc////\\kk.exe(注:连续的\或/都被Windows认为是一个\,所以有效)
物理路径自然要以盘符开头,所以正则开始是:^[a-zA-Z]:[\\/]+
接着是后面的子目录,目录或文件名按Windows规定,不允许出现<>/\|:"*? 以及 回车换行共11个字符,所以匹配子目录的正则是:[^\<\>\/\\\|\:""\*\?\r\n]+[\\/]+,因为可能有多级子目录,也可能没有子目录,所以匹配全部子目录的正则就是:(?:[^\<\>\/\\\|\:""\*\?\r\n]+[\\/]+)*,最后完整的正则就是:
^[a-zA-Z]:[\\/]+(?:[^\<\>\/\\\|\:""\*\?\r\n]+[\\/]+)*[^\<\>\/\\\|\:""\*\?\r\n]*$

9、需求:输入6~20位的密码,要求必须是大写字母、小写字母和数字的组合
完整的正则是:
^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])[a-zA-Z0-9]{6,20}$
另外一个使用平衡组的正则:
^(?:([0-9])|([a-z])|([A-Z])){6,20}(?(1)|(?!))(?(2)|(?!))(?(3)|(?!))$

10、需求:匹配HTML的a标签里的href,要求支持单引号、双引号或无引号的可能
可能的数据有:<a href='xxx' target='_self'> <a href=xxx target='_self'> <a href="xxx" target='_self'><a href="javascript:alert('1')"><a href='javascript:alert("1")'>
首先自然是匹配到href的正则:<a\s[^>]*href=,接着匹配引号,因为可能没引号,因此是:(['"])?,后面要判断出现了引号没有,用一个三目运算符:(?(1)yes|no)
如果前面出现了引号,用正则:(?:(?!\1).)*\1,表示不等于前面引号的多个字符+前面的引号(\1表示引用)
完整的正则是(当然这个正则没有考虑更复杂的情况,比如<a href="javascript:alert(\"1\")">,这个等你来扩展吧):
<a\s[^>]*href=(['"])?(?(1)((?:(?!\1).)*)\1|([^\s>]*))

 发表于:2013-05-28 15:06:42

 4.1 程序或站点里的所有线程代码,都必须用try捕获全部异常,因为线程异常未处理,会导致整个进程崩溃,导致程序退出,或站点重启

 
4.2 类的静态构造函数代码,必须捕获所有可能出现的异常,如果静态构造函数出现异常,则在应用程序或web站点重启之前,都始终保持异常状态,无法恢复,如下面的a.txt文件不存在,那么即使后来主动创建了a.txt文件,异常也无法恢复:
     static class StaticTest
    {
        static StaticTest()
        {
            try
            {
                using (var sr = new StreamReader(@"c:\a.txt"))
                {
                    sr.Read();
                }
            }
            catch(Exception)
            {
                
            }
        }
 
        public static int max(int a, int b)
        {
            return a > b ? a : b;
        }
    }
 
 
4.3 SqlParameter的Value不能为null,会出现参数未提供异常,但可以为String.Empty
 
4.4 创建文件或文件夹时,名字不允许为以下系统保留字:CON、PRN、NUL、AUX、COM1至COM9、LPT1至LPT9,也不能用使用以上名称+"."作为文件名的开头部分,如"CON.ABC.TXT"是不允许的。
 
 发表于:2013-05-28 14:55:23

 程序或站点里的所有线程代码,都必须用try捕获全部异常,因为线程异常未处理,会导致整个进程崩溃,导致程序退出,或站点重启,注意:下面的代码是无效的

try
{
    new Thread(method).Start();// 这个method方法如果出现异常,依旧会导致程序退出,或站点重启
}
catch
{
}

public void method()
{
try

{
    要执行的业务逻辑// 在这里加try,才是真实有效的
}
catch
{
}
}

 发表于:2012-12-15 11:14:54
更新于:2012-12-15 11:15:55

今天在进行数据同步时,通过SqlDataReader读取全部的100万数据,传给SqlBulkCopy复制到其它数据库,在复制前需要检查源表和目标表结构是否一致,如果不一致就不同步,直接返回,代码大致如下:

using (SqlDataReader reader = SqlHelper.ExecuteReader(m_sourceCon, "select * from tb"))
{
    if(源表结构与目标表结构不一致){
        MessageBox.Show("结构不一致");
        return;
    }
    // 开始SqlBulkCopy的代码
}

在上面的代码里,tb表的数据量为100万条,每次走到MessageBox后都会超时,即使调整ExecuteReader的Timeout为更长时间也不行,始终是30秒左右超时,通过修改代码反复调查,发现是走到using的结束时超时,于是在if代码框里增加reader.Close(),果然,就是在Close的时候导致的超时

在同事的帮助下,发现在MSDN上对Close方法有个说明:
Close 方法填写输出参数的值、返回值和 RecordsAffected,从而增加了关闭用于处理大型或复杂查询的 SqlDataReader 所用的时间。 如果返回值和查询影响的记录的数量不重要,则可以在调用 Close 方法前调用关联的 SqlCommand 对象的 Cancel 方法,从而减少关闭 SqlDataReader 所需的时间。

原来如此,把ExecuteReader代码修改一下,把SqlDataReader的Command对象返回,并通过调用Command.Cancel()方法来避免这个问题,修改后的代码:

SqlCommand command;
using (SqlDataReader reader = SqlHelper.ExecuteReader(m_sourceCon, "select * from tb", out command))
{
    if(源表结构与目标表结构不一致){
        command.Cancel();
        MessageBox.Show("结构不一致");
        return;
    }
    // 开始SqlBulkCopy的代码
}

至此,问题解决,比较郁闷的就是,SqlHelper.ExecuteReader方法需要多加一个out参数

 发表于:2012-12-14 14:27:52
更新于:2012-12-14 16:22:28

小时候听过一个泡茶的故事,正常的顺序是:烧开水20分钟,准备茶叶1分钟,清洗茶杯5分钟
正常情况下,大家都是先烧开水,在等水烧开的过程中,去准备茶叶和清洗茶杯,而不会等水烧开后,再去准备茶叶和清洗茶杯,这样可以节约6分钟时间。

同样的,最近经常处理一些数据同步的工作,比如把数据从SqlServer同步到Redis或MongoDB里去,很多人的代码都是,先读取SqlServer的数据,经过一番处理,再写入Redis,这里犯了泡茶那样的错误,这些工作都是一步步来的,比如读取数据10秒,处理1秒,写入Redis5秒,每批数据都要耗时16秒,代码简单叙述如下:
while(true){
    // 从SQLServer获取一批数据;
    DataTable dt = "select top(2000) * from tb where id>@lastid order by id"
    if (dt.Rows.Count <= 0)// 没有数据就退出
        break;

    处理数据代码
               
    WriteToRedis(item1.Key, item1.Value);
   
    lastid = (int)dt.Rows[dt.Rows.Count-1]["id"];// 用于获取下一批数据
}

实际上,我们也可以像泡茶那样并行处理,来节约一些时间,微软给我们提供了一个类:System.Threading.ReaderWriterLockSlim
这个类用于管理资源访问的锁定状态,可以实现多线程读取或独占式写入,简单的说,就是对一个数据,读取多个线程一起读取,但是写入只允许独占,也就是在写入时,不允许其它线程来读取或写入,而且必须其它线程的读写操作都完成,才能得到写锁,代码如下:

//全局定义一个读写线程锁
static ReaderWriterLockSlim m_RWLock = new ReaderWriterLockSlim();

while(true){
    // 从SQLServer获取一批数据;
    DataTable dt = "select top(2000) * from tb where id>@lastid order by id"
    if (dt.Rows.Count <= 0)// 没有数据就退出
        break;
    lastid = (int)dt.Rows[dt.Rows.Count-1]["id"];// 用于获取下一批数据

    处理数据代码1(如果SQLServer慢,处理数据代码放入线程)

    //阻塞,直到获取到写锁(写锁只允许一个线程读取数据)
    //只有下面的ReadLock全部释放,这一步才能继续,
    //这样可以读取数据库和写入Redis同步进行,节省读取数据库的时间
    m_RWLock.EnterWriteLock();
    //获取到写锁后,马上释放
    m_RWLock.ExitWriteLock();
   
    // 使用线程写入到Redis
    ThreadPool.UnsafeQueueUserWorkItem(state => {
        try
        {
            //获取读锁, 允许多个线程同时操作Redis
            m_RWLock.EnterReadLock();
            try
            {
                处理数据代码2(如果Redis慢,处理数据代码放EnterWriteLock前面)
               
                WriteToRedis(item1.Key, item1.Value);
            }
            finally
            {
                m_RWLock.ExitReadLock();
            }
        }
        catch (Exception ex)
        {
            LogHelper.WriteException("异常:", ex);
        }
    }, null);
}

 

代码复杂了许多,不过为了效率,忍忍吧,呵呵

 发表于:2012-11-22 15:35:37

51CTO推荐专题:jQuery从入门到精通

DOM树

首先,可视化一个HMTL文档的DOM树是很有帮助的。一个简单的HTML页面看起来就像是这个样子:

jQuery

 

事件冒泡(又称事件传播)

当我们点击一个链接时,其触发了链接元素的单击事件,该事件则引发任何我们已绑定到该元素的单击事件上的函数的执行。

  1. $('a').bind('click', function() { alert("That tickles!") });

因此一个单击操作会触发alert函数的执行。

jQuery

click事件接着会向树的根方向传播,广播到父元素,然后接着是每个祖先元素,只要是它的某个后代元素上的单击事件被触发,事件就会传给它。

jQuery

在操纵DOM的语境中,document是根节点。

现在我们可以较容易地说明.bind()、.live()和.delegate()的不同之处了。

.bind()

  1. $('a').bind('click', function() { alert("That tickles!") });

这是最简单的绑定方法了。JQuery扫描文档找出所有的$(‘a’)元素,并把alert函数绑定到每个元素的click事件上。

.live()

  1. $('a').live('click', function() { alert("That tickles!") });

JQuery把alert函数绑定到$(document)元素上,并使用’click’和’a’作为参数。任何时候只要有事件冒泡到document节点上,它就查看该事件是否是一个click事件,以及该事件的目标元素与’a’这一CSS选择器是否匹配,如果都是的话,则执行函数。

live方法还可以被绑定到具体的元素(或“context”)而不是document上,像这样:

  1. $('a', $('#container')[0]).live(...);

.delegate()

  1. $('#container').delegate('a', 'click', function() { alert("That tickles!") });

JQuery扫描文档查找$(‘#container’),并使用click事件和’a’这一CSS选择器作为参数把alert函数绑定到$(‘#container’)上。任何时候只要有事件冒泡到$(‘#container’)上,它就查看该事件是否是click事件,以及该事件的目标元素是否与CCS选择器相匹配。如果两种检查的结果都为真的话,它就执行函数。

可以注意到,这一过程与.live()类似,但是其把处理程序绑定到具体的元素而非document这一根上。精明的JS’er们可能会做出这样的结论,即$('a').live() == $(document).delegate('a'),是这样吗?嗯,不,不完全是。

为什么.delegate()要比.live()好用

基于几个原因,人们通常更愿意选用jQuery的delegate方法而不是live方法。考虑下面的例子:

  1. $('a').live('click', function() { blah() });
  2. // 或者
  3. $(document).delegate('a', 'click', function() { blah() });

速度

后者实际上要快过前者,因为前者首先要扫描整个的文档查找所有的$(‘a’)元素,把它们存成jQuery对象。尽管live函数仅需要把’a’作为串参数传递以用做之后的判断,但是$()函数并未“知道”被链接的方法将会是.live()。

而另一方面,delegate方法仅需要查找并存储$(document)元素。

一种寻求避开这一问题的方法是调用在$(document).ready()之外绑定的live,这样它就会立即执行。在这种方式下,其会在DOM获得填充之前运行,因此就不会查找元素或是创建jQuery对象了。

灵活性和链能力

live函数也挺令人费解的。想想看,它被链到$(‘a’)对象集上,但其实际上是在$(document)对象上发生作用。由于这个原因,它能够试图以一种吓死人的方式来把方法链到自身上。实际上,我想说的是,以$.live(‘a’,…)这一形式作为一种全局性的jQuery方法,live方法会更具意义一些。

仅支持CSS选择器

最后一点,live方法有一个非常大的缺点,那就是它仅能针对直接的CSS选择器做操作,这使得它变得非常的不灵活。

欲了解更多关于CSS选择器的缺点,请参阅Exploring jQuery .live() and .die()一文。

更新:感谢Hacker News上的pedalpete和后面评论中的Ellsass提醒我加入接下来的这一节内容。

为什么选择.live()或.delegate()而不是.bind()

毕竟,bind看起来似乎更加的明确和直接,难道不是吗?嗯,有两个原因让我们更愿意选择delegate或live而不是bind:

Ÿ 为了把处理程序附加到可能还未存在于DOM中的DOM元素之上。因为bind是直接把处理程序绑定到各个元素上,它不能把处理程序绑定到还未存在于页面中的元素之上。

Ÿ 如果你运行了$(‘a’).bind(…),而后新的链接经由AJAX加入到了页面中,则你的bind处理程序对于这些新加入的链接来说是无效的。而另一方面live和delegate则是被绑定到另一个祖先节点上,因此其对于任何目前或是将来存在于该祖先元素之内的元素都是有效的。

Ÿ 或者为了把处理程序附加到单个元素上或是一小组元素之上,监听后代元素上的事件而不是循环遍历并把同一个函数逐个附加到DOM中的100个元素上。把处理程序附加到一个(或是一小组)祖先元素上而不是直接把处理程序附加到页面中的所有元素上,这种做法带来了性能上的好处。

停止传播

最后一个我想做的提醒与事件传播有关。通常情况下,我们可以通过使用这样的事件方法来终止处理函数的执行:

  1. $('a').bind('click', function(e) {
  2. e.preventDefault();
  3. // 或者
  4. e.stopPropagation();
  5. });

不过,当我们使用live或是delegate方法的时候,处理函数实际上并没有在运行,需要等到事件冒泡到处理程序实际绑定的元素上时函数才会运行。而到此时为止,我们的其他的来自.bind()的处理函数早已运行了。

转载自:http://developer.51cto.com/art/201103/249694.htm

使用jQuery的live()方法绑定事件,有时会出现重复绑定的情况,当点击一个按钮时,此按钮所绑定的事件会并执行n遍。
你可以使用die()方法,在live()方法绑定前,将此元素上的前面被绑定的事件统统解除,然后再通过live()方法绑定新的事件。这样上面的情况就不会发生了。

另外,一个曲线使用stopPropagation的方案,在父节点的事件里,判断e.target,如果是子节点,直接return

 发表于:2012-11-06 16:46:37
更新于:2012-11-21 11:16:37

刚刚接到响一声电话,很郁闷,最近老接到,于是决定记录下来所有接过的响一声电话:
2012.11.15 12:42    13173277472,
2012.11.13 06:55    18615125097,
2012.11.06 16:35    13783732958,
2012.10.18 12:33    15140576027,
2012.10.12 22:04    18347241549,
2012.10.11 12:35    13630578454,
2012.09.28 01:24    15666215615,
2012.09.23 03:18    15083438974,
2012.09.22 01:02    15662744745,
2012.09.21 01:45    15034728904,
2012.09.12 02:42    13754483341,
2012.08.23 17:12    15764956190
 

以上是手机里能找到的所有记录了,以后再有,哥再写
 


©2008 Beinet.cn 版权所有