最新日志

发表于:2007-12-8 15:35:00
标签:无标签

0

Web中使用多线程来增强用户体验

前几天遇到了一个问题,我在页面逻辑里需要调用一个webservice,处理一个比较耗时的操作,但是我不需要知道其返回值。于是我希望asp.net能像winform一样使用自动生成的webservice异步方法

你是不是想说:在页面调用webservice的时候,直接调用其异步实现不就完了吗?

这其实是行不通的,为了实现异步调用,我们需要对页面进行小小的改动,在Page元素里加上IsAsync=true

我们很快就会发现这样做的问题:

让我们测试一下吧,现在我们在一个webservice的Helloworld方法中放入一个Thread。Sleep(10000),然后调用他的异步实现。通过调试,我们可以发现虽然程序运行至HelloworldAsync时,非常快速的返回并往下运行,但是当所有逻辑处理完成后,页面并不Response,而是硬生生等待我们的线程睡醒了才返回。

可是如果我希望真正做到调了不管怎么办呢? 

sync

你可以使用Thread,或者ThreadPool,自己来启动一个线程,我推荐使用ThreadPool,这样的话,这些线程都会被iis的线程池管理起来,不会造成崩溃

我们来分析一下这两种模式的运用有什么特点

WebService自带的异步模式为下图的模式

Async1

主线程调用子线程执行一个耗时操作(work1),同时执行一系列同步操作(w2...w5),然后交给w1返回

这种模式适合于work1有返回的情况,并且为了让work1得到充分的工作时间,异步调用的过程开始的越早越好,对web程序设计者而言,这里有一个很重要的问题:线程占用。。

刚才我们谈过,asp.net中每个请求都会有有一个线程来处理,而可以使用的线程是有限的,服务器会使用一个线程池来管理线程,当线程耗尽,ok,新来的请求只能蹲着排队,所以对web开发者而言,线程是个宝贵的资源,所以这个方案在并行处理的同时也增加了耗尽线程池的风险,毕竟一个请求造成了多个线程

 

用线程池来实现的模式属于下图

Async2

这种模式适合无返回的情况,这种情况下,对子线程的调用应该越晚越好,我们可以看到,主、子线程共存的时间越短,我们的稀缺资源线程就越安全,请注意的是,也许总的执行时间不会比同步的情况更少,但是我们很快就返回了用户界面,所以用户体验能够得到提高

使用web多线程的缺点 :

看了上面的叙述,你也许会说,那干脆把我所有的调用都改成异步调用吧,你尽管去做吧,绝对是一场灾难,因为在异步的同时,一定一会产生一个新的线程等待调用的返回,即使你调用函数的返回值为void,所以异步调用的负面效果将是会产生许多子线程,所以注意当你的调用非常耗时,这个子线程也将长期占用你的线程池,如果这样的调用大量出现,照样会消耗掉所有的可用线程

那么什么情况下适合在web上使用哪种多线程模式呢

我们来看看这段伪代码,他的用途是提交一个报告,方法传入一个报告,并从一个WebService中获得一些报告的内容,接着插入数据库,然后在文件服务器上生成一个报告文件,最后发出一个通知,让我们逐条命令的过一下这个方法,看看什么地方适合改为异步调用?(记得我们的讨论都是基于web的,关于桌面运用的多线程请参考 多线程总结一)

public void CreateReport(Report report){

//从webservice上取得报告的一些信息,不取得这些信息报告,报告是不完整的,是不能提交的

Report fullreport=CallWebService(report);

//插入数据库,很重要的工作

InsertIntoDataBase(fullreport)

try{

//生成报告文件,这里是一个耗时而且容易出错的操作

WriteStaticFile(fullreport)

}

catch{//记录错误日志。。。。}

//这个只是通知邮件

CallMailService2(fullreport)

}

第一条语句CallWebService()从一个webservice里加载一些报告的内容,这个是业务逻辑相关的,因为如果不加载的话报告内容是不完整的,不能提交,显然不能改为异步调了不管的模式,在这里你可以尝试模式一,但是这个改动是没有作用的,因为其他所有的过程,包括插入数据库,生成报告都依赖于这个方法的返回,所以如果我们在这里使用异步的话,其他的所有操作都必须等待他的返回,所以采用异步除了多增加了线程以外,一点时间也不能节省

再来看插入数据库,和上面一样也没有必要使用异步调用

生成报告这里比较有趣,确实他是一个和逻辑息息相关的操作,但是通过分析代码,我们可以看出,虽然报告生成是一个重要业务步骤,但是并没有严格到说"如果不能生成报告,就必须回滚上面的操作",并且如果操作失败,在catch中也仅仅是记录了日志,并没有需要尝试重写的逻辑,(很有可能另外的某个程序或者某人,会定时查看日志,发现有错误就重新生成文件)也就是说,就这段代码而言,生成也可以算一个额外逻辑,那么自然也可以去异步操作.可是:千万注意!!

由于生成报告需要的时间较长,那么生成报告的子线程会长时间运行,长期无法返回线程池,如果请求量太大,频率太快,那就会耗尽线程资源了.

平心而论,这个问题其实不是异步造成的,即使时同步调用,执行此操作也需要化肥很长时间,调用量太大,频率太快,也会造成排队.而且由于返回时间太长,用户体验也不会好,所以我们的这个改造应该是有益的

(注:关于报告生成,我在与一个同事讨论这种思想的时候,他就认为这个地方应该有一个写入队列,因为显然生成文件的速度和其他处理速度是不匹配的,这确实是一个比较合理的做法)

二毛五 2007-12-08 15:35 发表评论

点击此处查看原文 >>

系统分类: 汽车电子   |    用户分类: 无分类    |    来源: 无分类

评论(0) | 阅读(876)
发表于:2007-12-7 19:52:00
标签:无标签

0

ScottGu博客之翻译-第8部分--使用自定义的SQL语句

  感谢Dudu为我们带来运行速度更快的服务器!庆祝新服务器已上线!  

在上几周中我写了一个概述了LINQ to SQL的帖子系列。LINQ to SQL是集成在.NET Framework3.5中的O/RM(对象关系映射)的实现,它让你非常容易地用.NET类来生成关系型数据库的模型。然后你可以用LINQ 表达式对它来进行查询,更新,插入删除。 下边是我的该系列的前七篇的帖子的链接:

 在前两篇帖子中 (Part 6 and Part 7)我描述了如何用LINQ to SQL数据模型通过数据库的存储过程和用户自定义的函数来查询和检索数据。在今天的博客中我将讨论一下如何选择使用存储过程来更新、插入、删除数据。

自从我写了那些帖子之后,许多人问我的问题之一就是“如果我想完全控制linq to sql的sql表达式,并且我又不想用存储过程--我该怎么做?”今天的博客将会讲述这个问题--并且讨论一下如何使用自定义的sql表达式来控制你的linq to sql 数据模型类,对其插入、更新和删除。

和LINQ to SQL一起使用LINQ 查询表达式

为了完成今天帖子要讲述的内容,让我们假设已经用VS2008中的LINQ to SQL ORM设计器为Northwind数据库定义一个如下的数据模型类:(在本系列的第2部分Part 2 中讲述了如何用设计器定义此数据模型类):

 

 在本系列的第3部分(Part 3),我讲述了如何用在VB和C#中支持的新的LINQ语言来对上面的数据模型类进行查询,并且返回一个代表了数据库中的行/列关系的对象。

 

例如,我们可以向我们的数据模型的DataContext类中添加一个"GetProductsByCategory"的帮助方法 ,该方法用LINQ查询从数据库中进行查询并返回一个Product对象集合:

VB:

C#:

 

一旦我们定义了LINQ帮助方法,我们可以写如下的代码,用LINQ的帮助方法来检索产品并且对结果进行遍历:

VB:

 

当"GetProductsByCategory"方法被调用时, LINQ to SQL ORM将会运行动态的SQL来检索产品数据。你可以在LINQ to SQL Debug Visualizer中查看这个LINQ表达式最终是如何生成的。

Using Custom SQL Queries with LINQ to SQL

和LINQ to SQL一起使用自定义的SQL查询

在上面的例子中,我们没有写任何的SQL代码来查询数据库和检索出强类型的产品对象。取代之的是,linq to sql orm会自动的将linq表达式翻译为sql语句,并且使用生成的sql语句对数据库进行操作。

可是,若是我们想完全控制对我们的数据库进行操作的sql语句,并且不想让linq to sql为我们自动生成的话,该怎么做呢?实现这个目的的方法之一是使用在本系列的第 六(Part 6)和第七( Part 7)部分讲解的存储过程。另外一个方法是使用在DataContext基类中的"ExecuteQuery"帮助方法,使用我们提供的自定义的sql表达式。

使用ExecuteQuery方法

 

ExecuteQuery方法将sql查询表达式作为参数,和一系列的我们可以选择使用参数列表。使用这一功能我们可以对数据库执行原始的sql语句(包括自定义的多表之间的连接)。

使ExecuteQuery方法真正有用的是它允许你声明以何种方式将sql表达式返回的值进行格式化。你可以通过如下两种方式来实现:或者向方法中传递一个类型对象作为参数,或者使用一个本方法的generic-based的版本。

例如,我们可以修改原来生成的GetProductsByCategory()的帮助方法-使用LINQ表达式--来替代ExecuteQuery方法来执行我们自己的原始的SQL表达式对数据库进行操作并返回"Product"对象:

VB:

C#:

 

然后我们可以调用GetProductByCategory()帮助方法,代码可以和前面的代码完全相同:

 

但是和前面的不同的是,对数据库进行操作的是我们自定义的SQL表达式--而不是linq表达式生成的动态sql语句。

为更新自定义SQL表达式和对象跟踪

默认情况下,当你用LINQ to SQL从数据模型对象中检索数据时,它会跟踪所有的变化并且当你对对象进行更新时更新这些变化。如果你调用DataContext中的"SbumitChanges()"方法,它将会启动一个事务,并且将所有的变更更新至数据库中。我本系列的第四部分Part 4中对这一点进行的较深刻地讲解。

ExecuteQuery()的其中一个比较酷的我是,它完全参与跟踪和更新模型中。比如,我们可以写如下的代码查询属于某一类别的产品并且将它们的价格打折10%:

因为我们将ExecuteQuery()方法调用的GetProductByCategory()方法的结果集转换为"Product"的类型,LINQ to SQL知道跟踪返回的Product对象。当我们调用Context对象中的"SubmitChanges()"方法时,它们将会被保存至数据库中。

自定义类中的自定义SQL表达式

ExecuteQuery()方法允许你指定任何类来作为SQL查询的返回值类型。该类不是必须用LINQ to SQL ORM设计器生成的或者实现了某些自定义的接口-你可以将旧的类指定给它作为它的返回值类型。

例如,我可以定义一个新的ProductSummary类,该类含有Product的属性是Product类的属性的一个子集,包括如下这些属性(注意新的C#的自动属性Automatic Properties特性):

 

然后我们可以在NorthwindDataContext中生成一个将该类作为返回值类型的GetProductSummariesByCatetory()帮助方法。注意下面的SQL声明是如何只请求Product中的我们需要的属性的值的--ExecuteQuery()方法自动处理它返回的ProductSummary对象:

 

然后我们可以执行这个帮助方法并且用下面的代码来对结果集进行遍历:

 

用于插入、更新、删除的自定义的SQL表达式

除了对查询使用自定义的SQL表达式,我们也可以执行它们来进行插入、更新、删除的逻辑。

我们可以通过如下方式实现这个目的:在DataContext的一个局部类中生成一个适当的插入、更新、删除的局部方法。然后使用ExecuteCommand方法来写我们需要执行的SQL语句。例如,为了为产品类覆盖删除的方法,我们可以定义如下的一个DeleteProduct局部方法:

 

然后如果我们写如下的代码从数据库中移除一个特定的产品实例,LINQ to SQL将会调用DeleteProduct方法--该方法将会引起我们自定义的SQL语句替代自动生成的SQL语句:

 

总结

LINQ to SQL ORM自动生成并运行动态的SQL语句来对数据库进行查询、更新、插入和删除。

在一些高级的场景中,或者在你想完全控制执行的SQL语句的情况下,你依然能够自定义ORM来或者使用存储过程,或者使用你自己定义的SQL表达式来替代原来它自动生成的SQL语句。这在创建和扩展你的数据层的时候给你提供了非常大的灵活性。

在接下来的本系列的帖子中,我将描述一些余下的LINQ to SQL概念,包括:单表继承,延迟/提前加载,优化并发冲突,处理多个场景。

希望这些对你有所帮助,

Scott



韩现龙 2007-12-07 19:52 发表评论

点击此处查看原文 >>

系统分类: 汽车电子   |    用户分类: 无分类    |    来源: 无分类

评论(0) | 阅读(913)
发表于:2007-12-7 18:52:00
标签:无标签

0

介绍TemplateEngine - 另外 - 高报酬寻VB高手做个PARTIME项目

     摘要: TemplateEngine它不是一个产品的名字.它只是我的MVC框架中的一个子部分.
这个引擎负责把对象数据呈现成文本数据.它有一些特征:
1. 指令简单 - 内置不超过10个常用的指令.
2. 基于XPath - 直接使用XPath查找对象,并且可以使用XPath强大的语法和函数.
3. 容易扩展 - 无论是指令还是XPath函数都可以自定义.
4. 解析超快 - 基于其语法特点,解析模板结构非常快.
-
另外 - 高报酬寻VB高手做个PARTIME项目 http://www.cnblogs.com/Lostinet/archive/2007/12/08/987655.html
-  阅读全文

Lostinet 2007-12-07 18:52 发表评论

点击此处查看原文 >>

系统分类: 汽车电子   |    用户分类: 无分类    |    来源: 无分类

评论(0) | 阅读(817)
发表于:2007-12-7 18:14:00
标签:无标签

0

ExtJS调用WCF系列-----实现JSON传递

     摘要: 首先我们打开我们的VS 新建一个Asp.Net WebApplication Project,(不要给我说新建网站,我讨厌那个东东) 命名为ExtJSAndWCFChapter1 如图: 接下来我们在该项目中新建一个实体类文件和一个AJAX—Enabled WCF SERVICE,分别命名为Employee.cs 和EmployeeService.svc 下面去ExtJS.Com网站下...  阅读全文

小庄 2007-12-07 18:14 发表评论

点击此处查看原文 >>

系统分类: 汽车电子   |    用户分类: 无分类    |    来源: 无分类

评论(0) | 阅读(865)
发表于:2007-12-7 18:00:00
标签:无标签

0

ExtJS调用WCF系列

ExtJS调用的服务器端目前有三种实现方式:
一种是网页的方式,他的Content-Type:是application/x-www-form-urlencoded,这种方式适用范围比较广泛,只要是能输出网页的服务器端环境都可以。ExtJS官方网站上的例子基本上都是这种形式,服务器端的环境是PHP,http://cmsoft.cnblogs.com/ 是实现这种方式的.net版本,不过让我这样来写dotNet代码我可不愿意。

一种是WebService的方式,也就是通过XML在服务器和客户端传递数据的方式,在DotNet下这种实现方式比较复杂,也比较搞笑,原因是在服务器序列化的xml要在客户端用Asp.Net Ajax才可以反序列化,然后才能被ExtJS调用,我既然用了ExtJS框架,还得再用ASP.Net AJAX框架,实在不爽!

还有一种是WCF的形式,他的Content-Type是 application/json,其原理是基于JSON来在服务器端和客户端传递数据,我们必须得定义服务器端方法的输入,输出参数为JSON形式才可以,其次还得进行URL重写等(其实就是加个attribute),我觉得还是这种方式实现起来比较顺眼。

在google找到了这两篇文章http://www.hausertechnologies.com/wordpress/?p=33 和http://www.hausertechnologies.com/wordpress/?p=35  并经过我的琢磨,就琢磨出一些心得体会来,不敢独享,所以贴出来让园子里喜欢EXTJS和dotNet的朋友也一起体会体会。

我分为三节来讲述EXTJS调用WCF的系列,每节都有详细的步骤说明和截图,而且还提供源码,要是还有人不明白,就回家看看自己的耳朵和鼻子是不是都很大?开发环境是Visual Studio 2008 英文RTM版 和 EXTJS 2.0 后面没有RC的那个版本,也就是目前最新版

第一节:ExtJS调用WCF系列-----实现JSON传递

第二节:ExtJS调用WCF系列-----分页列表实现

第三节:ExtJS调用WCF系列-----添加,修改,删除



小庄 2007-12-07 18:00 发表评论

点击此处查看原文 >>

系统分类: 汽车电子   |    用户分类: 无分类    |    来源: 无分类

评论(0) | 阅读(946)
发表于:2007-12-7 17:45:00
标签:无标签

0

谈谈WPF中的CollectionView与CollectionViewSource (1)

     摘要: 本系列随笔将介绍WPF中对在表现层对数据列表进行的"高级加工",比如排序,分组,筛选,导航以及其它自定义视图,并且这不会影响到你的后台数据的实际存储.这是第一部分.  阅读全文

周银辉 2007-12-07 17:45 发表评论

点击此处查看原文 >>

系统分类: 汽车电子   |    用户分类: 无分类    |    来源: 无分类

评论(0) | 阅读(162)
发表于:2007-12-7 17:25:00
标签:无标签

0

Windows Embedded从入门到精通12月预告

 

进入12月“Windows Embedded从入门到精通”课程请来了两位从业经验丰富且技术功底深厚的讲师。两位老师都曾经在MEDC上有过精彩的演讲。这次Webcast选择的话题也都是实际开发经常遇到的难题,两位老师会分享自己的开发经验,来共同探讨内存泄露与调试、性能优化这些“高端”难题的解决方案。

Windows CE 内存泄漏的检测和防止

20071212日星期三下午 230

http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032361286&EventCategory=4&culture=en-US&CountryCode=US

 

讲座内容:

很多嵌入式设备是长时间不间断运行的,即使是些微的内存泄漏(Memory Leak),也会积少成多,对嵌入式系统带来灾难性的影响。本节课介绍 Windows CE 的内存管理机制,内存泄漏的检测方法和防范手段。

 

课程讲师:

黄文中 Windows Embedded MVP(微软最有价值专家)

黄文中先生,北京大学理学硕士,微软嵌入式系统培训讲师(Embedded Training Instructor),微软嵌入式系统最有价值专家(MVP For Windows Embedded),微软系统工程师(MCSE)在嵌入式操作系统定制、驱动开发及应用集成方面有很深的造诣。

 

技术等级:

Level 300

 

Windows CE 5.0/Windows Mobile调试与性能优化

20071226日星期三下午 230

http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032361320&EventCategory=4&culture=en-US&CountryCode=US

 

讲座内容:

通过认识Windows CE系统架构和运行机制,结合相应的调试工具和分析手段,定位系统瓶颈和问题点。

 

课程讲师:

滕建超 微软(中国)有限公司企业服务部咨询顾问

微软中国企业服务部咨询顾问,负责嵌入式行业的开发咨询。在车载电子及移动通讯行业有多年的从业经验。

 

技术等级:

Level 300

 



马宁 2007-12-07 17:25 发表评论

点击此处查看原文 >>

系统分类: 汽车电子   |    用户分类: 无分类    |    来源: 无分类

评论(0) | 阅读(173)
发表于:2007-12-7 14:29:00
标签:无标签

0

程序集版本最后一位使用SVN版本号的自动生成方法

     使用SVN进行源代码版本控制时,我们希望能够快速找到每个发布版本对应的源代码版本,现在可以通过在程序集的版本信息中增加SVN源码版本信息的方式来实现我们的要求。
      现在我们定义每个程序集的版本信息的最末段表示SVN的源码版本。详细定义如下:

程序集版本号分为4段,例如1.0.4.23。

  1. 第一段为主版本号,项目一但启动则不会更改。
  2. 第二段为次版本号,在项目功能做较大调整时增加,增量为1。
  3. 第三段为修订版本号,通常在解决缺陷或者细微功能变化时增加,增量为1或者2。该版本号分奇数和偶数两种。奇数表示测试版本,偶数表示稳定版本。
  4. 第四段为SVN源码版本号,该版本号通过脚本自动生成。
     使用脚本自动生成SVN版本号的先决条件:
  1. 安装TortoiseSVN;
  2. 源代码在SVN版本管理控制之下。
    修改项目设置,使之能够自动生成版本号:
  • 修改Properties\AssemblyInfo.cs文件,将程序集版本信息的最末一段改为$WCREV$。并增加一行"//最后发布时间:$WCDATE$"
例如:
[assembly: AssemblyVersion("1.1.0.$WCREV$")]
[assembly: AssemblyFileVersion("1.1.0.$WCREV$")]
//最后发布时间:$WCDATE$
  • 将AssemblyInfo.cs文件重名为AssemblyInfo.tpl,并添加到源代码管理。
  • 从源代码仓库中删除AssemblyInfo.cs,并排除它,使其不受版本管理
  • 添加本文中的GenerateAssemblyInfo.bat文件到Properties目录中,并添加到源代码管理。
  • 修改项目属性,在生成事件预生成事件命令行中添加以下命令。
"$(ProjectDir)\Properties\GenerateAssemblyInfo.bat" "$(ProjectDir)" .\Properties\AssemblyInfo.tpl .\Properties\AssemblyInfo.cs
     注意
  • 编译之前记得提交你的更改和更新别人的更改,这样才能确保版本号的正确。
  • 今后要对程序集信息进行修改时,请对AssemblyInfo.tpl文件进行修改。
  • 如果生成的AssemblyInfo.cs文件出现中文乱码,打开AssemblyInfo.tpl,在文件->高级保存选项中将文件编码改为UTF-8即可。

     脚本

GenerateAssemblyInfo.bat

 

      参考资料 Zealic 的 通过 TSVN 自动更新程序集版本信息 
 



浮云 2007-12-07 14:29 发表评论

点击此处查看原文 >>

系统分类: 汽车电子   |    用户分类: 无分类    |    来源: 无分类

评论(0) | 阅读(308)
发表于:2007-12-7 11:44:43
标签:EDN  new  

0

EDN new editon

It's edn new edition,fifth~~~

we get work hard for ednchina.com,because of we believe everybody need best service on line

点击此处查看原文 >>

系统分类: 自由话题   |    用户分类: 无分类    |    来源: 原创

评论(0) | 阅读(184)
发表于:2007-12-7 10:56:00
标签:无标签

0

url重写实现任意二级域名或多级域名(修正参数中断问题)

简要回顾:
    修改微软的URLRewrite能够对URL进行重写,这里要求对域名进行重写,实现http://1234.abc.com/ 到http://www.abc.com/show.aspx?id=1234的重写。
步骤:1、你的域名 http://www.abc.com/ 是泛解析的,并在IIS里添加了主机头为空的映射;
 2、修改微软的URLRewriter,要改两个地方
      (1).BaseModuleRewriter.cs

protected virtual void BaseModuleRewriter_AuthorizeRequest(object sender, EventArgs e)
        
{
            HttpApplication app 
= (HttpApplication) sender;
            Rewrite(app.Request.Url.AbsoluteUri, app);
        }

就是将  app.Request.Path 替换成了  app.Request.Url.AbsoluteUri 

      (2).ModuleRewriter.cs

for(int i = 0; i < rules.Count; i++)
            
{
                
// get the pattern to look for, and Resolve the Url (convert ~ into the appropriate directory)
                string lookFor = "^" + rules[i].LookFor + "$";

                
// Create a regex (note that IgnoreCase is set)
                Regex re = new Regex(lookFor, RegexOptions.IgnoreCase);

                
// See if a match is found
                if (re.IsMatch(requestedPath))
                
{
                    
// match found - do any replacement needed
                    string sendToUrl = RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath, re.Replace(requestedPath, rules[i].SendTo));

                    
// log rewriting information to the Trace object
                    app.Context.Trace.Write("ModuleRewriter""Rewriting URL to " + sendToUrl);

                    
// Rewrite the URL
                    RewriterUtils.RewriteUrl(app.Context, sendToUrl);
                    
break