关键词:周末 系统上线 加班 通宵

180 views 十二月 20, 09 by Timothy

周末之时,即是系统上线之日,周五下班后,和同事一起驱车去西河大吃兔子,一大份外加一中份,很是过瘾,也为晚上熬夜补充营养。接着回到办公室dota两把,午夜12点后开始系统调试、上线到生产环境,一直到第二天早上快7点,收拾东西闪人,发现车子没油了,郁闷,去对面的加油站加油,告知不能刷卡,只加了100块,更郁闷。随后一路狂飙回家,看了看表,7点半,天已经微微亮了,竟然发觉自己没有一点困意,看来偶通宵的功夫还真不是盖的。回到家,发现乖女已经醒了,洗脸洗脚,睡了……

Linq to Sql 之延迟加载与立即加载

405 views 十二月 20, 09 by Timothy

Linq的延迟加载

Linq to Sql中默认采用的模式就是延迟执行,所谓延迟执行,其实就是在获取对象本身时,并不会获取和其关联的其他对象,只有在访问其关联对象的时候,程序才会去加载关联对象的数据到内存中。这样的好处是程序不会在初次访问的时候,就加载大批量的数据,而是以一种延迟加载的方式进行处理,相对而言,对于系统和网络的性能开支会减小很多。对于一个默认的Linq to Sql查询,延迟加载就是其默认的设置,不过,在某些情况下,延迟加载并非完全“智能”,不但没有实现其本意,反而增大了网络流量和性能开支。下面我们以SQL Server中的演示数据库NorthWind来试验一下:

linq_context

?View Code CSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
LinqTestDataContext ctx = new LinqTestDataContext();
ctx.Log = Console.Out;
 
var result = ctx.Orders.Where(p => p.OrderID == 10251);
 
foreach (var t in result)
{
	Console.WriteLine("OrderID:" 
		+ t.OrderID 
		+ "-" 
		+ "OrderDate:" 
		+ t.OrderDate.Value.ToString("yyyy-MM-dd"));
}

通过Linq to sql查询所有OrderID为10251的订单信息,并输出订单编号和订单日期。通过显示Linq的日志输出,我们可以看到后台生成的SQL语句如下:

1
2
3
4
5
6
SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate], [
t0].[RequiredDate], [t0].[ShippedDate], [t0].[ShipVia], [t0].[Freight], [t0].[Sh
ipName], [t0].[ShipAddress], [t0].[ShipCity], [t0].[ShipRegion], [t0].[ShipPosta
lCode], [t0].[ShipCountry]
FROM [dbo].[Orders] AS [t0]
WHERE [t0].[OrderID] = @p0

输出的SQL看来还比较正常。下面我们再来改一下我们的程序:

?View Code CSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 foreach (var t in result)
            {
                Console.WriteLine("OrderID:" + t.OrderID 
		+ "-OrderDate:" 
		+ t.OrderDate.Value.ToString("yyyy-MM-dd") 
		+"-CustomerName:"
		+ t.Customer.ContactName);
                foreach(var m in t.Order_Details)
                Console.WriteLine("ProductID:" 
		+ m.ProductID 
		+ "-Price:" 
		+ m.UnitPrice 
		+ "-Amount:" 
		+ m.Quantity);
            }

出了输出订单相关信息外,还输出其关联对象:客户姓名、订单中的产品编号、单价、数量

再来看看输出的SQL语句:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate], [
t0].[RequiredDate], [t0].[ShippedDate], [t0].[ShipVia], [t0].[Freight], [t0].[Sh
ipName], [t0].[ShipAddress], [t0].[ShipCity], [t0].[ShipRegion], [t0].[ShipPosta
lCode], [t0].[ShipCountry]
FROM [dbo].[Orders] AS [t0]
WHERE [t0].[OrderID] = @p0
 
 
SELECT [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactT
itle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Coun
try], [t0].[Phone], [t0].[Fax]
FROM [dbo].[Customers] AS [t0]
WHERE [t0].[CustomerID] = @p0
 
 
SELECT [t0].[OrderID], [t0].[ProductID], [t0].[UnitPrice], [t0].[Quantity], [t0]
.[Discount]
FROM [dbo].[Order Details] AS [t0]
WHERE [t0].[OrderID] = @p0

我们可以看到,对于我们修改后的代码,程序向数据库请求了三条SQL语句,当然,这还不是最坏的情况,但是我们在这里的确看到延迟加载似乎“变了味道”,不但没有节省开支,反而增大了网络浏览。怎样才能改善这样的情况呢?

关于立即加载

其实我们知道,有很多扩展方法会导致延迟加载失效,而开始立即执行。当我们在调用诸如:ToList、ToDictionary、ToLookup或者ToArray之类的扩展方法之后,程序会将最终的结果存放到某个临时的变量集合中,并让所有的数据一次性的加载完成。

另外,还有一种方式,通过设置DataContext的DeferredLoadingEnabled属性为false,显示的关闭默认的延迟加载方式。

?View Code CSHARP
1
2
LinqTestDataContext ctx = new LinqTestDataContext();
ctx.DeferredLoadingEnabled = false;

 

这些方式虽然比较方便,但是还是有一定的局限性。例如,简单的使用ToList只能解决一些简单的查询问题,而对于复杂的查询需求,ToList还是不能解决延迟取得子对象所引发的多次查询问题。并且,在大量数据被加载到内存中的时候,对内存的需求也是很大的。不过,幸好Linq to sql给我们提供了另外一套不错的方法。

使用DataLoadOptions实现对加载对象的优化

Linq to Sql提供DataLoadOptions,用以立即加载关联的对象数据,其中包含两种方法:

LoadWith方法,用于立即加载与主对象相关联的数据

AssociateWith方法,用于对关联对象的数据进行筛选,并加载

有了DataLoadOptions,我们就可以用如下的方式优化我们的查询中需要加载的对象:

?View Code CSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
            LinqTestDataContext ctx = new LinqTestDataContext();
            ctx.Log = Console.Out;
 
            DataLoadOptions dl = new DataLoadOptions();
            dl.LoadWith<order>(p => p.Customer);
            dl.LoadWith<order>(p => p.Order_Details);
            ctx.LoadOptions = dl;
 
            var result = ctx.Orders.Where(p => p.OrderID == 10251).ToList();
 
            foreach (var t in result)
            {
                Console.WriteLine("OrderID:" + 
		t.OrderID 
		+ "-OrderDate:" 
		+ t.OrderDate.Value.ToString("yyyy-MM-dd") 
		+"-CustomerName:"
		+ t.Customer.ContactName);
                foreach(var m in t.Order_Details)
                Console.WriteLine("ProductID:" 
		+ m.ProductID 
		+ "-Price:" 
		+ m.UnitPrice 
		+ "-Amount:" 
		+ m.Quantity);
            }

对于我们开发者而言,需要注意的是,对于同一个DataContext实例,DataLoadOptions只能设定一次,并且一旦设定,就无法更改。

接下来,运行程序,看看优化后,程序向数据库服务器请求的的SQL:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate], [
t0].[RequiredDate], [t0].[ShippedDate], [t0].[ShipVia], [t0].[Freight], [t0].[Sh
ipName], [t0].[ShipAddress], [t0].[ShipCity], [t0].[ShipRegion], [t0].[ShipPosta
lCode], [t0].[ShipCountry], [t3].[OrderID] AS [OrderID2], [t3].[ProductID], [t3]
.[UnitPrice], [t3].[Quantity], [t3].[Discount], (
    SELECT COUNT(*)
    FROM [dbo].[Order Details] AS [t4]
    WHERE [t4].[OrderID] = [t0].[OrderID]
    ) AS [value], [t2].[test], [t2].[CustomerID] AS [CustomerID2], [t2].[Company
Name], [t2].[ContactName], [t2].[ContactTitle], [t2].[Address], [t2].[City], [t2
].[Region], [t2].[PostalCode], [t2].[Country], [t2].[Phone], [t2].[Fax]
FROM [dbo].[Orders] AS [t0]
LEFT OUTER JOIN (
    SELECT 1 AS [test], [t1].[CustomerID], [t1].[CompanyName], [t1].[ContactName
], [t1].[ContactTitle], [t1].[Address], [t1].[City], [t1].[Region], [t1].[Postal
Code], [t1].[Country], [t1].[Phone], [t1].[Fax]
    FROM [dbo].[Customers] AS [t1]
    ) AS [t2] ON [t2].[CustomerID] = [t0].[CustomerID]
LEFT OUTER JOIN [dbo].[Order Details] AS [t3] ON [t3].[OrderID] = [t0].[OrderID]
 
WHERE [t0].[OrderID] = @p0
ORDER BY [t0].[OrderID], [t2].[CustomerID], [t3].[ProductID]

可以看出,之前的分三次向数据库提交sql的情况,现在被程序优化为一条带LEFT JOIN的关联查询,而获取关联数据。三次SQL请求,被优化为一次,从而减少了数据库和网络流量开支,由此看来DataLoadOptions的好处不言而喻。

一点小结

延迟加载与立即加载,并无孰优孰劣之区别,在某些情况下,需要我们根据自己的需求和实际情况来选择来进行选择。

写在女儿半岁之际

278 views 十二月 07, 09 by Timothy

还有三天,到2009.12.10,就是女儿半岁的日子了,半年来,小女一天一个样,比起刚生下来的时候,老练了许多。今天来给她打扮打扮,拍照留恋,希望小女健康成长,嘿嘿。真期待她走路,叫老爸的那一天……

OLYMPUS DIGITAL CAMERA         OLYMPUS DIGITAL CAMERA

淘宝玩偶已收到

214 views 十二月 06, 09 by Timothy

淘宝最近为了推广淘江湖,推出免费送玩偶的活动,只要你接到好友送的玩偶,就能领取名额,然后再推荐给你的几个朋友,你就能收到好友送的玩偶实物。今天收到了Ven同学送的“阳光男”,在此感谢。玩偶戴个帽子,还有滑板,而且都是可拆卸的,呵呵,很有意思!

IMAG0157IMAG0158

开源的作业调度框架:Quartz.NET

675 views 十二月 05, 09 by Timothy

Quartz.NET是一套开源的作业调度框架,是最初由Java平台的企业级开源作业调度框架 Quartz 移植到.NET平台的。在sourceforge上,Quartz.NET的主页有这样的介绍: Quartz.NET is a full-featured, open source job scheduling system that can be used from smallest apps to large scale enterprise systems. (Quartz.NET是能应用在小到轻量级的应用程序,大到重量级的企业级系统中的全功能的开源任务调度系统)并且,值得令人信服的是,Quartz.NET已经在生产环境中得以用,并得到了良好的反馈。

回想一下,在小到普通的应用程序,大到企业级项目中,我们常常会遇到需要定时轮询和调度的场景,简单点的需求是每隔固定的秒数或者分钟、小时进行轮询,复杂点的是每周的某个时刻,或者每月,或者每年才执行一次,又或者更复杂的情景,某些天需要执行,某些天不执行。用Windows自带的计划任务,能够实现简单的逻辑,如果要用程序实现这样的逻辑,想必也很复杂了。其实,用Quartz能很好的应付这些情况。

Quartz.NET的核心模块分为几个部分,Scheduler、Job、JobDetail、Trigger

Scheduler:实现调度的主体,负责调度任务的开始、结束,Scheduler中包含已注册的JobDetail和Trigger,并且,当Trigger中的条件得以触发时,Scheduler负责执行和Trigger相关联的Job,实现任务的调度。
Job:需要被调度的任务,Job必须实现IJob接口的Execute方法,而Execute方法的内容,其实也就是我们需要根据不同的需求自己实现的业务逻辑。
JobDetail:包含对Job的具体描述,包括Job的名称、所属的Group名称、以及Job的Type描述,用以Quartz.NET通过反射实现对Job的调用。
Trigger:触发器,描述调度的触发条件和时机。

Quartz.NET之所以没把Job和Trigger设计在一起,而是采用一种松耦合的方式,把Job和Trigger独立为两个不同的对象,原因是因为在Quartz.NET中,Job和Trigger可以建立一种一对多的关系,也就是可以对一个调度任务绑定多个Trigger,另外的好处是当某个Job的Trigger过期的时候,可以直接为Job绑定新的Trigger而不用重新定义和这个Trigger相关联的Job。

最初见到Quartz.NET,还是0.6的版本,一直躺在偶的硬盘里面,直到最近项目中遇到很多需要定时轮询处理的情况,突然想到了Quartz.NET,打开它在sourceforge的大本营,才发现Quartz.NET已经更新到1.0.1版本了。

Quartz.NET为我们提供了简洁的API,通过简单的例子,我们就可以很快上手和使用

在Quartz.NET中,所有的Job都必须实现IJob接口:

?View Code CSHARP
1
2
3
4
5
6
7
namespace Quartz
{
    public interface IJob
    {
        void Execute(JobExecutionContext context);
    }
}

JobExecutionContext 包含运行时的一些上下文信息,还可以用来传递参数

编写我们自己的Job,实现IJob接口:

?View Code CSHARP
1
2
3
4
5
6
7
8
9
10
11
12
using Quartz;
 
namespace ExampleJob
{
    public class TestJob : IJob
    {
        public void Execute(JobExecutionContext context)
        {
            Console.WriteLine("Job executed!");
        }
    }
}

然后就可以通过Scheduler来调度任务了

?View Code CSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 创建SchedulerFactory
ISchedulerFactory schedFact = new StdSchedulerFactory();
 
// 获取Scheduler实例
IScheduler sched = schedFact.GetScheduler();
sched.Start();
 
// 创建JobDetail
JobDetail jobDetail = new JobDetail("ExampleJob", "MyJobGroup", typeof(ExampleJob));
// 创建Trigger,每分钟触发一次
Trigger trigger = TriggerUtils.MakeMinutelyTrigger();
// 设定trigger的开始时间
trigger.StartTimeUtc = TriggerUtils.GetEvenHourDate(DateTime.UtcNow);
trigger.Name = "myTrigger";
sched.ScheduleJob(jobDetail, trigger);

这样,任务调度框架便会每分钟调度一次我们的Job,在控制台每分钟都能看到一句 ”Job executed!”,是不是很简单呢?

其实Quartz.NET还有很多方便开发人员的特性和高级功能,比如通过配置文件配置Job和Trigger,可以让你的调度程序更加灵活,以应对后续需求的变化,而不需要重新编译程序。另外,还有调度线程池、JobStore、Clustering等很多高级功能,等着我们去发现。

相关资源:

Quartz.NET 主页:http://quartznet.sourceforge.net

在sourceforge的Quartz.NET主页上,有入门教程供初学者查看:http://quartznet.sourceforge.net/tutorial/index.html

另外,博客园的张善友也把教程翻译成了中文的,供E文不好的同学学习和参考,地址:http://www.cnblogs.com/shanyou/archive/2007/08/25/QuartzNETtutorial.html

上网推荐的DNS设置

609 views 十二月 04, 09 by Timothy

由于某某原因,现在上网变得越来越不容易了,很多网站都经常莫名其妙的打不开,其中有一部分因素,就是遭到DNS劫持。所以,我一般不会用国内的DNS,因为国内的DNS会在解析域名时,“故意”犯错。比较好的方法就是使用国外的免费DNS,这段时间,一直用OpenDNS,效果还不错,今天Google也向公众发布了免费的DNS服务,ping测试了一下,速度还比较快,所以立马采纳了,呵呵。

至此,推荐给大家比较不错的DNS最佳设置(DNS的ping值,电信、网通可能有稍许差异):
Google Public DNS服务:速度不错,家中上网,ping值平均220ms
首选DNS:8.8.8.8
备用DNS:8.8.4.4

补:  Ben同学提供的另外一个Google未披露的DNS 4.3.2.1 目前测试来看,速度应该是最快的

Open DNS服务:家中上网,ping值平均在400ms
首选DNS:208.67.222.222
备用DNS:208.67.220.220

另外,还有个不错的DNS:家中上网,ping值平均在500ms左右
4.2.2.2

目前看来,还是Google的DNS访问起来比较快,推荐设置为首选。

Blog 皮肤下载—Minyx 2.0 Lite

450 views 十二月 02, 09 by Timothy

本Blog使用的皮肤,名字叫 Minyx 2.0 Lite,三栏样式,用起来还算不错,一直比较喜欢。不过,现在的效果已经是是被我改过后的了,原本的样式可以看这里:http://www.pengpengblog.com/ 右边的两栏和左边的一栏各占50%,并且三栏并不是占满整个屏幕的,这样对于展现代码而言比较窄,所以动手修改了CSS布局,让三栏铺满整个屏幕,并调整了后两栏的宽度和一些边栏的布局,让左边显示文章内容的一栏变得更大。有喜欢的朋友可以下载了试试,也可以根据自己的喜好再修改。

下载地址

初试Chrome OS

260 views 十一月 23, 09 by Timothy

这两天最热门的东东,无非是Chrome OS了,虽然正式的Chrome OS面世,需要等到一年后左右。但其相关报道已经占据了各大论坛和站点的首页。在Google公布Chromium OS开源项目的同时,国外已经有大牛将源码编译成了操作系统镜像并开放下载。我也迫不及待的Down了一份镜像,放在VirtualBox上玩玩。安装十分简单,建立一个Linux系统的虚拟机,然后加载下载好的操作系统镜像即可。

首次运行,开机登录,使用Google帐号:
chromeos1

Google的理念,OS即浏览器,所有体验都在浏览器内进行……
chromeos2
从下载设置,可以看到后台基于Linux的文件系统
chromeos3

因为Chrome OS的桌面即浏览器,这也让网上对于此系统的评价褒贬不一,在我个人看来,这是一次创造性的尝试,用户再也不用担心安装操作系统、驱动程序、应用程序的繁琐,所有的应用都基于网络和浏览器,客户的程序只是一个瘦客户端,后台借助于强大的云计算服务实现对数据的处理和存储,而用户需要关心的只是自己的数据,而这些重要的数据,也会存放在网络中的云端。这种模式在现在看来,或许超前了一些,但对于传统的杀毒软件厂商和应用厂商来说不得不是一次很大的冲击,Chrome OS甚至会影响到未来微软操作系统的地位。嗯嗯,虽然现在的Chrome OS还不太成熟,不过按照Google的思路,将Chrome OS和GAE结合起来,充分运用云计算的优势,这或许将是一个很具有革命性意义的开端……

Page: 22 of 49 1 ... 18 19 20 21 22 23 24 25 26 ... 49