| 宏宇 的个人资料庄生晓梦迷蝴蝶,望帝春心托杜鹃照片日志列表 | 帮助 |
庄生晓梦迷蝴蝶,望帝春心托杜鹃懵懂无知的认不仅由于外界的各种因素而焦躁不安,以致永不得享受心灵的宁静;他还对神和万事都懵懂无知,若不痛苦,便无法生活,真正不痛苦时,也就不存在了. |
||||
|
2009/12/3 格言 功利是一部机器的目的和检验机器价值的根据,而善良只是人的目的和意愿。 ——【印度】泰戈尔《民族主义》 The early bird might get the worm, but the second mouse gets the cheese. 在英国一天的收获要达到国内15天的收获才不枉每个夕阳西下. 2009/12/2 Great 异步问题--什么堆栈已经优化之类的~~CER.NET 2.0 CER学习笔记
CER是.NET 2.0 CLR方面的重要改进,旨在帮助那些对稳定性高度苛刻的程序对付.NET Framework的不稳定因素。因为普通的程序很少会用到,所以一直没有对这个特性加以足够重视。现在碰巧在翻译书籍的过程中用到,就一起来学习一下。 首先,需要提到异步异常的问题。异步异常就是指OutOfMemoryException、StackOverflowException和ThreadAbortException等系统异常。说他们“异步”是因为他们可以在线程代码执行到任何地方的时候发生。一般的异常,比如FileNotFoundException是由代码自己产生的,因此可以用Try语句正常捕捉和处理。而异步异常则是CLR产生的。而且,这些异常都预示着非常严重的错误,代码自己通常都会手足无措。比方说内存耗尽了,代码自己即使Catch了也无济于事,都不知道刚刚哪一步出的问题,也不知道该怎么继续执行。ThreadAbortException通常是由Thread.Abort方法引发,如果要Abort的线程正在进行很关键的人物,比如修改一个全局对象的状态,那么发生ThreadAbortException可能会让整个程序的状态受损,进而产生错误的行为。因此,需要有种机制告诉CLR,我们要进行的事情很关键,不容打断,这就是CER——Constrained Execution Region。 声明CER很简单,先调用System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions()方法,再紧接一个Try...Catch...Finally块即可。注意,这个Try必须紧接着PrepareConstrainedRegions()方法,而且,只有Catch和Finally块的内容成为CER。如下所示 RuntimeHelpers.PrepareConstrainedRegions() Try Catch '注意,这里是CER Finally '这里也是CER End Try 一般情况下都用Finally块来做CER。CER与普通代码不同,在CER执行期间CLR不能发出异步异常。因此CLR就必须采取一些措施。首先CER会将ThreadAbortException推迟到CER结束之后才发生,这比较容易做到。第二,为了避免OutOfMemoryException,CLR会将CER中用到的所有方法(注意,这里是从代码静态观察,而不是实际调用的方法)以及这些方法所调用到的所有方法全都编译成本地代码,然后根据情况预测可能的内存不足并提前到CER之前引发。然而,这个方法并不能对付堆栈益处错误,所以这个方法会事先保留48K的栈空间以防万一。然而根据MSDN文档,StackOverflowException还是可能会发生的。 为了确保CER这种原理能够工作,首先CER之内不能在堆上进行任何分配操作,包括后台进行的分配操作。除了不能用New分配引用类型的对象之外,也不能进行装箱、线程同步锁操作或者访问多维数组。 刚才介绍到,CLR会事先编译CER中所有用到的方法以及它们各自调用的所有方法。那么聪明的人一定能看出一个问题,那就是通过委托和虚函数机制调用的方法无法事先准确判断,因而就无从准备。因此,RuntimeHelpers还提供了两个方法——PrepareMethod和PrepareDelegate。调用之前务必用这两个方法准备所有虚函数的实际版本和委托变量。使用CER是需要极其小心准备的,因此不是随随便便使用的特性。RuntimeHelpers还有许多其它方法对应各种有变数的情况。总之,CER的宗旨就是在执行之前将所有可以知道的情况尽数分析透彻以便提前判断CER中的操作到底有没有可能顺利完成。 下面用ThreadAbortException来做一个试验,因为这个异常是最容易引发的: Imports System.Runtime.CompilerServices Imports System.Threading Module Module1
Dim globalArray() As Integer
Sub Main()
globalArray = New Integer(50000000) {}
Dim t As New Thread(AddressOf Thread1) t.Start() t.Abort() t.Join() Console.WriteLine(AllEquals(globalArray, 100))
End Sub Function AllEquals(Of T)(ByVal arr() As T, ByVal value As T) As Boolean
For i As Integer = 0 To arr.Length - 1 If Not arr(i).Equals(value) Then Return False Next Return True End Function Sub Thread1()
RuntimeHelpers.PrepareConstrainedRegions() Try Finally For i As Integer = 0 To 50000000
globalArray(i) = 100 Next End Try
End Sub End Module
先把准备CER的代码注释掉,可以发现这个方法不是总能执行成功的,ThreadAbortException可能会将数组的操作打断,以至于留下不正常的状态。如果在你的计算机上该方法不会失败,可以尝试改变数组的大小。接下来应用CER,会发现出现异常时程序执行的速度剧烈下降,但是最终方法总能够成功地完成。这就是CER所带来的好处。 Thread.Abort()之前调用个Thread.Join()也能较好避免问题,原因不知道~~~~ 2009/11/2 最优解的不稳定性——完美的结果难以长久 http://www.sciencenet.cn/m/user_content.aspx?id=213830 2008-02-07 | 最优解的不稳定性——完美的结果难以长久 多 年的学习研究导致我一直不愿给学生或课题的东家最优解的结果,而只给他们能接受的可行解区域,原因无外乎我深知一般而言,各种事物发展的最优解是不稳定 的、脆弱的、几乎很难达到。没有不受时间影响的衡解,同时,最优解也受资源环境、政策和参与主体行为的变动的不确定性影响,其中,有关参与主体行为的影响 是最难研究的,至今也没有有效的普适性的结论,最多是案例研究的堆积,所以我得出如下论断,应该不失为有科学依据: 有关爱情——完美的爱情是需要经营的,但是结果却有好和不好之分。最容易保持的是一段缠绵悱恻的完美爱情,这就 是局部最优解,在一段时间内是容易发生的,但是,保有这个最优却是不现实的,如果不随环境和参与主体的行为变化进行行为调整,完美的爱情就变成昨日黄花。 这种结果不确定性并不能以具体参与者的行为而改变,因为这是一个多元函数的最优解,并不是每个变量都能控制的,如果不能控制的变量对解很重要,那么就不要 勉强你期望的最优解实现,那是做不到的事。经常有前辈鼓励有志者事竟成,恒心可达等等都是幻想,所以,这类事物的结果就当无解,尽好地左右你能够控制的变 量即可。但是,有时,却是可以控制爱情的结果,条件是:在准备成就爱情之前就已经预料到各种概率结果是你能够承受的,而且清楚不能控制的变量是无关事物发 展方向的,而你能牢牢把握的可控变量具有左右事物发展的特性,这样随着事物的发展,参与者可以通过经营各种可控变量,达到期望的结果(解)之上,尽管不是 最优,但是令你满意即可。 有关工作:明白自己的局限,有可为,更有太多的不可为。现在有太多的人因为总想工作的太完美而患上抑郁症,正像 崔永元所说,得抑郁症的人都是天才,都在挑战往往很难得到的最优解,而且总想从局部最优解向全局最优解发展,碰巧一步步爬上来了,压力之下会有战胜的笑 颜,但是,陷入无最优解的低谷时又如何能抵抗自我的否定,他们往往不知道,他们的事业往往是一个复杂的多元函数,很多决定性变量是随机的,不可控制的,我 们说历史创造英雄就是这个道理,人生往往能够理解不可达到最优,不去奢想“人定胜天、努力学习就有黄金屋和颜如玉”更现实。可惜,现在太多的人设想着一夜 致富,奢想一蹴而就的成功,所以周星驰的无厘头幻想在中国很有市场,更可悲的是,竟然有人患想中国对国际经济的发展迟缓能起到中流砥柱的作用。脱离环境的 要求和幻想是害人,这是许多老师和领导的害人之处,对学生和下属有太多的不切实际的要求就是害人害己。 其实,我一直认为,数学模型的可贵之处在于是客观现实的科学缩影,对于最优解的研究和理解,能够看清现实,指导人生和工作的行为。我们学会接受不如意的结果,去尽力控制可以控制的条件努力达到更好一点的结果,要优于追求最好的结果。 .Net 事务例子: 建立一个表,两个字段:一个叫 Id(自动编号)、一个叫 Priority(tinyint)。 有两条 SQL 语句: 一句是插入 Priority 为 1, 另一句是插入 Priority 为 256;如果不使用事务 结果: 第一句会插入成功 第二句由于超出 tinyint 范围,就会失败 使用事务时,数据库中将看不到任何记录;否则数据库中会有一条记录。 提供三种方法: /*1.Explicit Transaction * 提交、回滚事务都由程序员编程来决定 */ using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["MySqlServer"].ConnectionString))
{ conn.Open(); using (SqlTransaction tran = conn.BeginTransaction()) { using (SqlCommand cmd = new SqlCommand()) { cmd.Connection = conn; cmd.CommandType = CommandType.Text; cmd.Transaction = tran; try { cmd.CommandText = "insert into TranTable(Priority) values(1)"; cmd.ExecuteNonQuery(); cmd.CommandText = "insert into TranTable(Priority) values(256)"; cmd.ExecuteNonQuery(); tran.Commit(); Response.Write("Ok"); } catch (SqlException ex) { tran.Rollback(); Response.Write("Error:" + ex.Message); } } } conn.Close(); } Commit() 用来提交事务,如果产生了异常,就在 catch 块中用 Rollback 回滚事务,这样要么两条记录都插入了,要么一条都没插入。ADO.NET 显式事务占用资源少、速度快,但功能简单,只能管理单一对象和单一持久资源间的事务,比如想在数据库 B 插入失败,则回滚对数据库 A 的操作,就无法用这种 ADO.NET 显式事务来实现。 /*2.System.Transactions.CommittableTransaction 实现显式事务*/ using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["MySqlServer"].ConnectionString))
{ using (CommittableTransaction ct = new CommittableTransaction()) { conn.Open(); conn.EnlistTransaction(ct); using (SqlCommand cmd = new SqlCommand()) { cmd.Connection = conn; cmd.CommandType = CommandType.Text; try { cmd.CommandText = "insert into TranTable(Priority) values(1)"; cmd.ExecuteNonQuery(); cmd.CommandText = "insert into TranTable(Priority) values(256)"; cmd.ExecuteNonQuery(); ct.Commit(); Response.Write("Ok"); } catch (SqlException ex) { ct.Rollback(); Response.Write("Error:" + ex.Message); } } } conn.Close(); } 代码很像前面两节代码的综合,但功能比传统 .NET 事务技术强。 /*2.System.Transactions.TransactionScope 实现隐式事务*/ using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["MySqlServer"].ConnectionString))
{ using (TransactionScope ts = new TransactionScope()) { conn.Open(); using (SqlCommand cmd = new SqlCommand()) { cmd.Connection = conn; cmd.CommandType = CommandType.Text; try { cmd.CommandText = "insert into TranTable(Priority) values(1)"; cmd.ExecuteNonQuery(); cmd.CommandText = "insert into TranTable(Priority) values(256)"; cmd.ExecuteNonQuery(); ts.Complete(); Response.Write("Ok"); } catch (SqlException ex) { Response.Write("Error:" + ex.Message); } } } conn.Close(); } 可以看出 TransactionScope 并不来自于 SqlConnection,所以它可以管理多个 SqlConnection。并且它不管什么 Commit、Rollback,只管 Complete。TransactionScope 和数据库操作并没有直接关联,是什么造成了数据库操作以事务的形式执行的呢? 在连接字符串中,可以显示指定Enlist属性。如果Enlist=true,则SqlClient将自动检测是否存在事务,若存在,等登记到事务中,按事务执行;Enlist = false则不按事务执行。默认Enlist=true. 由于是SqlClient查找事务,所以Connection.Open必须在TransactionScope中调用,才能找到Transaction!! enlist [in'list] v. 徵募,参与,支持
|
||||
|
|