[转载][游戏开发利器]使用编辑器制作界面 - yung - 博客园

mikel阅读(1047)

[转载][游戏开发利器]使用编辑器制作界面 – yung – 博客园.

Morn UI一个显著优势就是Morn Builder(可视化编辑器),实现界面设计的所见即所得,《Morn简介及使用教程》文章中已经介绍了编辑器的简单使用方法,今天给大家介绍一下Morn UI每个组件的属性及在编辑器的简单使用方法。

打开编辑器,在E:\MornCompTest下创建了新UI项目命名为MornCompTest

复制基础组件到资源目录,然后F5刷新编辑器,即可看到资源组件树

然后Ctrl+N新建页面命名为ButtonTest,然后我们拖动左边的button到视图中,结果如下图:

morn_ui_40

编辑器分为菜单工具栏区,界面列表区,资源组件区,设计试图区,组件属性区,图层区等6个区域

基础属性

在组件属性区,每个组件都有自己的属性,每个组件都有一些公用属性,比如:

morn_ui_41 

name是组件实例的名字,x,y,width,height分别是组件坐标和宽高,var是组件实例的全局引用名,如果定义了这个,就可以在代码很方便的找到它。除了这些,morn ui所有组件还有下面基础属性

morn_ui_42 

属性这么多,美术同学要问怎么记呢?其实无需记忆,编辑器内鼠标放在属性文字上,会自动提示属性的名称和格式,很方便吧

下面我们一一介绍下各个组件的使用方法和属性含义

基础可视化组件

1.Label组件

morn_ui_label 

Label是文本,设置text可以显示其内容,设置isHtml=true后,会显示html内容

autoSize属性如果设置为left,就是自适应文本,宽度会随着文本长短的变化而变化

label还可以设置skin,作为文本的背景图片,同时支持sizeGrid,用来9宫格拉伸背景(详细格式请参考《深入了解Morn UI》)

stroke是文字描边,格式为(颜色,透明度,水平模糊量,垂直模糊量,强度,质量)比如红色描边可以定义为(0xff0000,1,5,5,2,1)

leading是段落之间的间距

2.TextInput组件

morn_ui_textinput 

TextInput是输入框,继承自Label,除了具有Label的属性外,额外多了上面三个属性,了解即可

3.TextArea组件

morn_ui_textarea 

TextArea是文本域,继承自TextInput,除了具有TextInput的属性外,额外多一个scrollBarSkin属性,可以用来设置滚动条皮肤

4.Button组件

morn_ui_button

Button是按钮组件,通过skin可以设置按钮皮肤,sizeGrid定义了按钮9宫格拉伸

labelColors是按钮文本在各种状态的颜色值,分别为(正常状态,鼠标经过状态,鼠标点击状态,禁用状态),比如(0x32556b, 0x32556b, 0x32556b, 0xC0C0C0)

toggle设定了是否是回弹按钮,其他一些属性和label类同

5.LinkButton,CheckBox,RadioButton组件

morn_ui_linkbutton

LinkButton是下划线按钮,CheckBox是多选按钮,RadioButton是单选按钮,三者均继承自Button,属性也和Button一样

6.Image组件

morn_ui_image 

Image是图形组件,具有url属性,设置url既可以是连接类,也可以是一个路径,支持异步加载,同时也可以设置9宫格拉伸

7.Clip组件

morn_ui_clip

Clip是位图切片,Clip类似flash的movieclip(动画剪辑),和Image类同,url既可以是资源连接类,还可以是一个路径动态加载

clip需要设置clipX属性和clipY属性,分别是图片行个数和列个数,支持多行多列,还可以设置clipWidth和clipHeight,这个是单个图标的宽高,程序会根据这个宽高算出clipX和clipY,比如上面图片行个数为10,列个数为1

Clip即可用来做icon,通过frame属性切换当前显示第几帧,又可作为位图动画,设置interval播放间隔进行播放,在编辑器选中clip,然后按回车键可以预览动画

frame就是当前切片显示的索引,从0开始

8.FrameClip组件

morn_ui_frameclip 

FrameClip是矢量图动画组件,和clip类似,不同的是FrameClip是Morn UI唯一基于矢量图的组件

它的skin对象为Movieclip的连接类,可以设置动画间隔并进行播放

FrameClip组件的主要用途是UI特效,毕竟矢量图动画特效比位图动画要小很多,并且效果也好。

9.ProgressBar组件

morn_ui_progressbar

ProgressBar是进度条组件,value范围是0到1,可以设置9宫格拉伸

10.Slider 滑动条

morn_ui_slider 

Slider是滑动条,可以通过滑动设置得到value值,min,max属性控制最大及最小值,tick设定了滑动单位值,allowBackClick定义是否允许点击背景滑动

11.HSlider,VSlider组件

HSlider是水平滑动条,VSlider是垂直滑动条,属性和Slider类同

12.ScrollBar组件 

morn_ui_scroll

ScrollBar是滚动条组件,其中scrollSize定义了每次滚动的数量

13.ComboBox组件

morn_ui_combobox

ComboBox是下拉框组件,labels属性可以设置下拉框列表值,比如label=“列表1,列表2”,用逗号隔开

visibleNum是下拉框列表一次显示的最大数量,如果label数超过这个数量,就会出现滚动条,通过scrollBarSkin可以设置滚动条皮肤

 

容器组件

1.Box组件

Box是容器组件,容器在界面上不能被直观看到,也不能通过拖动组件树创建,而是通过转换方式把某些内容转换为容器

比如界面中同时选中两个按钮,通过快捷键Ctrl+B转换为容器,那么两个按钮就被包含在Box内,作为一个整体来控制

morn_ui_43

 

选中一个容器,通过快捷键Ctrl+U,可以去除这个容器,和上面做相反的工作

2.Container组件

morn_ui_container 

Container是相对定位容器,继承自Box,增加了left,right,top,bottom等相对定位属性,同时增加了centerX,centerY等居中对齐属性

也可以通过Ctrl+B转换而来

3.Panel面板

morn_ui_panel

Panel继承Container,除了具有相对属性外,增加了滚动条和遮罩效果,无论里面的图片有多大,panel只会显示特定区域,通过滚动可以看到其他区域

4.Tab组件

morn_ui_tab

Tab是切换标签按钮组,可以设置labels属性设置标签,比如labels=“标签1,标签2”,多个用逗号隔开

direction定义了tab的布局方向,是水平还是垂直

假如Tab里面的按钮摆放不规则,颜色都不一样,想个性化,那么就需要自定义Tab布局,请参考教程《自定义Tab,Radiogroup,List》

5.RadioGroup组件

morn_ui_radiogroup

RadioGroup是单选按钮组,和Tab类似,可以设置labels=“单选1,单选2”进行设置,也可以通过direction属性选择布局的方向

RadioGroup也支持自定义布局,请参考教程《自定义Tab,Radiogroup,List》

6.List组件

morn_ui_list 

创建List:

添加一个label并选中,Ctrl+B转换为Box,设置Box的name属性为render,再选中Box通过Ctrl+B转换为List,设置List的行数,列数和间隔属性即可(分别为repeatX,repeatY,spaceX,spaceY)。

为list添加滚动条:
双击list,进入list内部,拖动一个滚动条到list内,修改name属性为scrollBar,即可自动识别,详细可参看Demo示例

最终结构如下:

<List x="214" y="274" repeatX="1" repeatY="5" spaceX="0" spaceY="5" var="list">
<Box x="0" y="0" name="render">
<Label text="label" x="27" y="4" name="label"/>
</Box>
<VScrollBar skin="png.comp.vscroll" x="89" y="3" width="15" height="150" name="scrollBar"/>
</List>

List和Tab一样,可以个性化自定义,请参考教程《自定义Tab,Radiogroup,List》

List是列表组件,继承自Box,repeatX,repeatY分别是列表项x,y方向每页最多显示的数量,spaceX和spaceY是列表项之间的间隔值,scrollSize是每次滚动的个数

List是比较常用的组件之一,同时也是最复杂,最灵活的组件,List还有很多高级用法,请参考教程《List高级使用教程》

7.ViewStack组件

morn_ui_viewstock

ViewStack是视图导航器组件,作为一个容器,用来存储多个视图,通过selectedIndex进行切换显示

使用方式:选择要包含进ViewStack的对象,分别命名为item0,item1,item2…,然后全选,Ctrl+B转换为ViewStack容器

最终结构如下:

<ViewStack x="364" y="328">
<Label text="view1111" name="item0" x="0" y="0"/>
<LinkButton label="view222" x="47" y="0" name="item1"/>
</ViewStack>

8.页面嵌套

morn_ui_uiview 

页面嵌套类似Flex的自定义控件,可以把一个界面嵌套到另外一个界面内,只需选中一个界面,拖动到另外界面内部即可

这样做可以实现自定义的显示组件,同时达到多界面复用的效果,还可通过修改此控件的runtime属性来设置嵌套界面的逻辑类

了解更多页面嵌套内容,可以参考教程《页面嵌套的使用》

视图组件

1.View组件

View是视图类,一个界面就是一个视图,视图类实现了界面结构的解析,这里具有很大的灵活性

在创建界面的时候,会让你选择用哪种视图类,你甚至可以自定义自己的视图类,封装自己的逻辑,然后在编辑器让界面都继承自此自定义视图类,这就是Morn UI自定义灵活性的又一表现,详情请参考教程《自定义页面基类》

2.Dialog组件

Dialog是对话框类,继承自View,在view基础上增加了show,popup,close等弹出对话框方法,同时增加了拖拽,模式窗口等功能

全部组件集合如下图:

morn_ui_44

游戏开发所用的组件,Morn UI都精炼的提供了,这么多功能,仅仅给你的代码增加30多K的大小,真正的轻量级

并且每个组件都是经过深思熟虑,同时保证简单好学好用,又要高性能,并且可视化布局,还考虑到自定义扩展等特性

这一切组件,全部开源,你可以任意改动和扩展,开发适合自己的需求东西,Morn UI的一个重要特性就是灵活性,易扩展

所有这些,均免费,甚至可以商业应用,如果你再犹豫,我和我的小朋友就要惊呆了

[转载]Visual Studio的配色方案,支持vs2005、vs2008、vs2010 - 灵雨飘零 - 博客园

mikel阅读(1230)

转载Visual Studio的配色方案,支持vs2005、vs2008、vs2010 – 灵雨飘零 – 博客园.

Visual Studio的配色方案,支持vs2005、vs2008、vs2010

 

 

Schemes

Top-rated | Latest | Recently updated

  • rated

    166
    57716

    dls

    94701

    views

    public class Snippet : IThemeable {
    static void Main() {
    if(“hello”.Length < (43 ^ 2))
    new Uri(“http://there.com”);
    }
    } // “Son of Obsidian”

    Ocean

    advanced 10 months ago, updated 9 months ago  Adam

 

更多下载http://studiostyl.es/schemes

[转载]前端基于easyui的mvc扩展 - ahl5esoft - 博客园

mikel阅读(1301)

[转载]前端基于easyui的mvc扩展 – ahl5esoft – 博客园.

背景

  由于MVC的前端是基于JQuery.validate和JQuery.validate.unobtrusive来实现的,但是当我们要使用其他的ui组件且组件本身就带有完整的验证功能的话,那么要让它们配合起来是有些麻烦的,比如:easyui。

介绍

MVC主要提供了一下几个验证特性来支撑前端的验证:  

  • CustomValidationAttribute:指定一个用于验证目标成员的验证类型和验证方法。
  • DataTypeAttribute:指定要与数据字段关联的附加类型的名称。
  • RangeAttribute:用于验证数值字段的值是否在指定的范围之内。
  • RegularExpressionAttribute:用于验证字符串字段的格式是否与指定的正则表达式相匹配。
  • RequiredAttribute:用于验证必需数据字段。
  • StringLengthAttribute:用于验证目标字段的字符串长度是否在指定的范围之内。
  • CompareAttribute:用于验证目标字段的值是否与另一个字段值一致,在用户注册场景中可以用于确认两次输入密码的一致性。
  • RemoteAttribute:提供使用 JQuery 验证插件远程验证程序的特性。

  以上大部分来自System.ComponentModel.DataAnnotations.dll,最后2个是来自System.Web.Mvc.dll

 

  而easyui则是基于validatebox可自定义验证规则以及派生出datebox、numberbox、combobox等控件,来实现form表单输入控件的一套完成的验证体系(详情可参考:www.jeasyui.com),easyui的验证代码如下:

<inputclass="easyui-validatebox validatebox-text"name="Name"required="true"missingmessage="用户名不能为空!"validtype="regular['^\\w+$', '用户名格式不正确!']"value="admin"type="text">

实现

了解了以上的2方提供的验证支持,那么我们就可以将mvc提供的验证解析为支持easyui验证的前端html代码了,根据以上的资料我们可以发现以下几个可直接转换的规则,实现代码大致如下:

var attribute = validationAttrs.FirstOrDefault(attr => attr isRequiredAttribute);if(attribute !=null){
    tag.AddAttribute("required","true");
    tag.AddAttribute("missingMessage", attribute.ErrorMessage);}

attribute = validationAttrs.FirstOrDefault(attr =>!(attr isRequiredAttribute));if(attribute ==null)return;if(attribute isStringLengthAttribute){var stringLengthAttr = attribute asStringLengthAttribute;
    tag.AddAttribute("invalidMessage", stringLengthAttr.ErrorMessage);
    tag.AddAttribute("validType","length[{0}, {1}]", stringLengthAttr.MinimumLength, stringLengthAttr.MaximumLength);}elseif(attribute isRegularExpressionAttribute){var regularAttr = attribute asRegularExpressionAttribute;
    tag.AddAttribute("validType","regular['{0}', '{1}']", regularAttr.Pattern.Replace("\\","\\\\"), regularAttr.ErrorMessage);}elseif(attribute isRangeAttribute){var rangeAttr = attribute asRangeAttribute;
    tag.AddAttribute("validType","range[{0}, {1}, '{2}']", rangeAttr.Minimum, rangeAttr.Maximum, rangeAttr.ErrorMessage);}elseif(attribute isCompareAttribute){var compareAttr = attribute asCompareAttribute;
    tag.AddAttribute("validType","eq['[name={0}]', '{1}']", compareAttr.OtherProperty, compareAttr.ErrorMessage);}

以上代码中把RequiredAttribute和其他的验证规则区分开来 是因为RequiredAttribute会生成独立的required=”true”,而其他的验证规则都是公用validType属性的,至于js验 证规则内的regular、range、eq的验证规则并不是easyui内部提供的,而是额外进行扩展的,js代码如下:

$.extend($.fn.validatebox.defaults.rules,{
    eq:{
        validator:function(value, param){this.message = param[1];return value == $(param[0]).val();}},
    range:{
        validator:function(value, param){this.message = param[2];return value >= param[0]&& value <= param[1];}},
    regular:{
        validator:function(value, param){this.message = param[1];var reg =newRegExp(param[0]);return reg.test(value);}}});

有了以上这些生成规则以后,我们就可以通过扩展HtmlHelper<TModel>来实现类似@Html.EditorFor(model => model.Name)这样的调用了,大致代码如下(这里以validatebox为例):

publicstaticMvcHtmlStringValidateText(thisHtmlHelper htmlHelper,Expression<Func<TModel,object>> expression){ModelMetadata modelMetadatum =ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);PropertyInfo property =typeof(TModel).GetProperty(modelMetadatum.PropertyName);TagBuilder tag =newTagBuilder("input");ValidationAttribute[] validationAttrs;if(property.TryGetAttributes(out validationAttrs)){//请阅读转换规则代码}returnMvcHtmlString.Create(tag.ToString());}

有了以上基础代码之后,我们就可以使用@Html.ValidateText(m => m.Name)来创建基于easyui的验证控件了。

效果

//类:publicclassAccountView{privatestring m_Name =null;[Required(ErrorMessage="用户名不能为空!")][RegularExpression(@"^\w+$",ErrorMessage="用户名格式不正确!")][DisplayName("用户名:")]publicstringName{get{return m_Name;}set{ m_Name = value;}}}//页面:@Html.LabelFor(m => m.Name)@Html.ValidateText(m => m.Name)//生成的内容为顶部easyui html示例代码

  正确:

  

  必填提示:

  

  验证失败:

  

结尾

  以上便是今天所有内容了,后面还有其他的扩展功能,敬请期待,谢谢各位!

[转载]推荐一些常用感觉不错的jQuery插件 - 紫尘 - 博客园

mikel阅读(1203)

[转载]推荐一些常用感觉不错的jQuery插件 – 紫尘 – 博客园.

     JQuery插件繁多,下面是个人在工作和学习中用到过感觉不错的,特此记录。

UI:

jquery UI(官方的UI插件,很好很强大兼容性好,灵活性很强,有十几套主题可供选择)

jQuery EasyUI (现在很受欢迎的一套UI,方便集成,但会有一些小问题,灵活性也有所不足,有些地方需要手动调整,前提是你要先从凌乱的代码中找到它的位置)

布局:

layout ( 布局?css不就够了吗? 尝试下layout把,非常适合管理系统布局,它将会带给你意想不到的惊喜,全面的demo文档,入手再简单不过)

masonry  层叠网格布局库 想让你的网站更炫更酷,内容的展现更具美感吗? 网上铺天盖地的瀑布流布局,使用它可以简单友好地实现,这仅仅是它的一种应用方式,更多惊喜期待你的尝试。

对话框:

artDialog(国产强大美观兼容性好)

fancybox  功能齐全,它除了可以加载DIV,图片、图片集、Ajax数据,还能加载SWF影片,iframe页面等等。

jQueryUI.dialog ( JQuery官方UI插件,可单独使用,很好用,别忘了引入核心支持文件)

表单验证:

jquery-validation(大家都在用,用了很多年,用过都说好,附带无刷新验证用户名是否存在)

form (无刷新表单提交)

数据表格:

datatables (关于数据表格,有它就够了,多种数据源,高灵活性,jQueryui主题支持,你想要的它都考虑到了,全功能文档,在国外它很受欢迎)

消息框:

  jquery-msgbox ( 感觉不错)

自动完成:

jqueryui.autoComplete ( 自动完成,我只用autoComplete,只会用这一个 0.0~ )

菜单:

accordion  美丽优雅的手风琴, 给你不一样的菜单栏

Tab:

jqueryui.tab ( 大爱,当然如果你需求比较简单,完全可以手写一下 )

树:

zTree ( 国产经典,强大好用 )

JQuery Treeview(经典老款)

图片查看:

lightbox ( 很好用,很炫目 )

noobSlide ( 全功能展示,多种风格任你挑选 )

basic-slider ( 简单的,就是好用的 )

上传:

uploadify ( 简单,易用,功能强大 )

日期选择:

datePicker  功能完备,兼容性好,大街小巷都是它,12306都是它,无力吐槽了。

色彩选择:

moorainbow (不错)

特别推荐

infinitescroll ( 最后的当然是重量级,无限滚动 – 自动加载,无尽的页面。本质上它是预取后续页面的内容,并将其添加到用户的当前页面直接。相当给力 )

 

插件为我们日常工作提供了方便,减轻了负担,但编程开发:自身实力强大才是立身之本,善用工具,绝不依赖,方是正理。万不能陷入知其然不知其所以然的境地,共勉之~

[转载]程序员最重要的技能 | 36氪

mikel阅读(932)

[转载]程序员最重要的技能 | 36氪.


什么才是程序员最有价值的技能?怎样才能成为一名成功的开发者呢?我敢打赌,在你的职业生涯中你至少问过自己一次这样的问题。你找到答案了吗?你认为自己搞清楚了没有?

许多年轻的程序员会告诉你,伟大的开发者最重要的技能是对自己所用语言的掌握。当然,你得对 C#、 F#、C++、Java、Ruby、Haskell 或什么别的语言娴熟于心。然而,语言本身并不能提供足够的技能让你完成桌面或 web 应用。

“那要不就是对平台的知识了,”你又问自己。也许甚至是整个平台体系,如果你仔细思考一下的话。比方说,这有可能意味着要知道 Windows API 或 iOS 开发的工具或库。可是,你再想一下。如果趋势变了的话又会怎样?如果项目转向另一个平台的话又会怎样?如果你只具备前一个平台的知识的话,你还会是一名伟 大的程序员吗?我不这么认为。

“对!我知道了。肯定是解决问题和分析性思维的能力”,你几乎对着我吼起来了。事实上你是对的。没有一个好的开发者是不具备分析性思维的。但是,问题解决仍然不是你应该具备的最重要技能。

“如果不是编程知识的话,那一定就是编程激情。你每天都得学点新东西。不能停止,你得热爱它。”的确,你是对的,尽管这并非最重要的能力,但已经接近了。让你从好的开发者变成伟大的开发者的,是编程的激情,尤其是学习的激情。

然而,还有一个技能更有价值,那就是沟通

许多时候这一点被低估了,可如果不使用沟通技能的话你一天都过不了。而且,你要沟通的还不仅仅是客户。还包括你的同事,分享你的想法,用不侮辱人的 方式辩论,说服你的老板应该采取你的方式。此外,还有还要汇报状态更新,解释发生的事情。你每天都要沟通,而且要沟通得当,如果你要成为伟大的开发者的 话。

这就是我要发文章谈演讲这个似乎不相干话题的原因。我认为从中你可以学到很多东西,如果你对此感兴趣的话你可以继续学习 coursera 的课程(英文)。

[转载]《Troubleshooting SQL Server》读书笔记-CPU使用率过高(上) - Joe.TJ - 博客园

mikel阅读(925)

[转载]《Troubleshooting SQL Server》读书笔记-CPU使用率过高(上) – Joe.TJ – 博客园.

第三章 High CPU Utilization.

CPU使用率过高问题很容易被发现,但是诊断却不是很容易。CPU使用过高很多时候会成为其它问题的替罪羊,所以在确认和故障诊断时要抽丝剥茧。

调查CPU压力

三个主要的工具:性能监视器,SQLTrace,DMV.

性能监视器:首先用它来确认是SQL Server还是其它进程使用了过多的CPU。主要计数器有:

Processor/ %Privileged Time :在特权模式下进程线程执行代码所花时间的百分比。基本可以认为是Windows核心使用的CPU
Processor/ %User Time :处理器处于用户模式的时间百分比。应用程序的使用的CPU。
Process (sqlservr.exe)/ %Processor Time :SQLServer.exe线程使用处理器执行指令所花的时间百分比。

还有一些与SQL Server相关CPU消耗的计数器:

SQLServer:SQL Statistics/Auto-Param Attempts/sec
SQLServer:SQL Statistics/Failed Auto-params/sec
SQLServer:SQL Statistics/Batch Requests/sec
SQLServer:SQL Statistics/SQL Compilations/sec
SQLServer:SQL Statistics/SQL Re-Compilations/sec
SQLServer:Plan Cache/Cache hit Ratio

SQLTrace: 通过Profiler生成SQLTrace脚本,进行服务器端跟踪,来获得高CPU使用时详细信息。

DMV:a. 使用sys.dm_os_wait_stats来得到signal wait,确认CPU压力的程度.

b. 使用sys.dm_os_wait_stats和sys.dm_os_schedulers观察等待类型

c. 使用sys.dm_exec_query_stats和sys.dm_exec_sql_text找出高CPU使用的执行计划和对应的查询

d. 使用sys.dm_os_waiting_tasks观察当前与CPU使用相关等待类型

e. 使用sys.dm_exec_requests正在执行的查询的资源使用状况

 

调查CPU相关的等待统计:请求执行前,包含请求的会话必需等待,SQL Server会记录等待原因和时间。通过sys.dm_os_wait_stats查询这些信息。

     信号等待时间(Signal wait time):sys.dm_os_wait_stats的wait_time_ms表示等待类型的总共等待时间,signal_wait_time_ms表示线程收到段义和到重新执行间的等待时间,

                                               这些时间主要花在runnable队列里,是纯CPU等待。

     通过以下查询得到信号等待的时间比率:

SELECT  SUM (signal_wait_time_ms) AS TotalSignalWaitTime , 
         ( SUM (CAST(signal_wait_time_ms  AS NUMERIC(20, 2)))  
           / SUM (CAST(wait_time_ms AS NUMERIC(20, 2)))  * 100  ) 
                         AS PercentageSignalWaitsOfTotalTime 
FROM    sys .dm_os_wait_stats

也可以查询各类资源等待的比率,下面是等待top 10:

SELECT TOP ( 10 ) 
        wait_type , 
        waiting_tasks_count , 
         ( wait_time_ms - signal_wait_time_ms ) AS resource_wait_time  , 
        max_wait_time_ms , 
         CASE waiting_tasks_count  
           WHEN 0  THEN 0 
           ELSE wait_time_ms / waiting_tasks_count  
         END  AS avg_wait_time 
FROM    sys .dm_os_wait_stats 
WHERE    wait_type NOT  LIKE '%SLEEP%'    -- remove eg. SLEEP_TASK and 
                                        -- LAZYWRITER_SLEEP waits 
         AND  wait_type NOT  LIKE 'XE%'  
         AND  wait_type NOT  IN -- remove system waits    
( 'KSOURCE_WAKEUP', 'BROKER_TASK_STOP', 'FT_IFTS_SCHEDULER_IDLE_WAIT' , 
  'SQLTRACE_BUFFER_FLUSH', 'CLR_AUTO_EVENT', 'BROKER_EVENTHANDLER', 
  'BAD_PAGE_PROCESS', 'BROKER_TRANSMITTER' , 'CHECKPOINT_QUEUE', 
  'DBMIRROR_EVENTS_QUEUE', 'SQLTRACE_BUFFER_FLUSH', 'CLR_MANUAL_EVENT', 
  'ONDEMAND_TASK_QUEUE', 'REQUEST_FOR_DEADLOCK_SEARCH' , 'LOGMGR_QUEUE', 
  'BROKER_RECEIVE_WAITFOR' , 'PREEMPTIVE_OS_GETPROCADDRESS', 
  'PREEMPTIVE_OS_AUTHENTICATIONOPS', 'BROKER_TO_FLUSH'  ) 
ORDER  BY wait_time_ms DESC

与CPU相关的等待类型主要有SOS_SCHEDULER_YIELD,CXPACKET和CMEMTHREAD

SOS_SCHEDULER_YIELD: SQL Server计划程序是协同的多任务计划程序。查询占用一小段时间的CPU后自发地让出CPU给后面的查询,

并且回到可运行队列等待重新被运行,这种等待就是SOS_SCHEDULER_YIELD。

如果此等待时间在sys.dm_exec_requests或者sys.dm_os_waiting_tasks过多,则表示有高CPU使用的查询需要优化或者需要增加CPU。

CXPACKET:多处理器运行并行查询时,当同步多个线程间的查询处理器交换迭代器时出现。

CMEMTHREAD:等待同步内存对象。有些内存对象是不请允许并发访问的,当多个线程试图访问此内存对象时,就会等待。

调查计划程序队列(scheduler queues):scheduler_id<255的是隐藏的系统计划程序,如DAC,备份等。

SELECT  scheduler_id  , 
        current_tasks_count, 
        runnable_tasks_count
FROM    sys.dm_os_schedulers
WHERE    scheduler_id < 255
      current_task_count表示每个计划程序上的任务数,runnable_task_count表示runnable队列中等待CPU的任务。
找出高CPU消耗的查询
      主要使用sys.dm_exec_query_stats和sys.dm_exec_sql_text。下面是占用CPU时间的TOP 10查询:
SELECT TOP ( 10 ) 
         SUBSTRING(ST.text, ( QS .statement_start_offset / 2  ) + 1, 
                  ( ( CASE statement_end_offset 
                         WHEN -1 THEN DATALENGTH (st.text) 
                         ELSE QS .statement_end_offset  
                       END  - QS .statement_start_offset ) / 2  ) + 1) 
                  AS statement_text , 
        execution_count  , 
        total_worker_time / 1000 AS total_worker_time_ms  , 
         ( total_worker_time / 1000 ) / execution_count 
                  AS avg_worker_time_ms  , 
        total_logical_reads , 
        total_logical_reads / execution_count  AS avg_logical_reads , 
        total_elapsed_time  / 1000 AS total_elapsed_time_ms , 
         ( total_elapsed_time  / 1000 ) / execution_count 
                  AS avg_elapsed_time_ms , 
        qp .query_plan  
FROM    sys .dm_exec_query_stats qs  
         CROSS  APPLY  sys .dm_exec_sql_text(qs.sql_handle ) st  
         CROSS  APPLY  sys .dm_exec_query_plan(qs.plan_handle) qp  
ORDER  BY total_worker_time DESC
值得注意的是有些情况下缓存计划是会被清除的,如内存压力,数据库状态改变等。使用了with recompile的SP和option (recompile)提示的语句不会缓存执行计划。
当查询因为某些原因被重编译(统计信息改变,架构改变等),如果经常发生,则会让执行时间统计变得不准确。所以最好是每隔一段时间抓取缓存计划信息,然后汇总对比。

[转载]《Troubleshooting SQL Server》读书笔记-CPU使用率过高(下) - Joe.TJ - 博客园

mikel阅读(931)

[转载]《Troubleshooting SQL Server》读书笔记-CPU使用率过高(下) – Joe.TJ – 博客园.

第三章 High CPU Utilization.

CPU使用率过高的常见原因

  查询优化器会尽量从CPU,IO和内存资源成本最小的角度,找到最高效的数据访问方式。如果没有正确的索引,或者写的语句本身就会忽略索引,

  又或者不准确的统计信息等情况下,查询计划可能不是最优的。

  有些查询计划可能对只对某种条件下的查询是高效,而不是所有条件下都是。

缺失索引

    索引的缺失,会导致查询处理的行数大大超出必要的行数,从而加重CPU和IO的负载。简单的例子:

复制代码
SELECT  per .FirstName  , 
        per.LastName , 
        p.Name  , 
        p.ProductNumber , 
        OrderDate , 
        LineTotal , 
        soh.TotalDue  
FROM    Sales.SalesOrderHeader  AS soh 
         INNER  JOIN Sales.SalesOrderDetail sod  
                       ON soh.SalesOrderID = sod.SalesOrderID  
         INNER  JOIN Production.Product  AS p  ON sod.ProductID  = p.ProductID 
         INNER  JOIN Sales.Customer AS c  ON soh.CustomerID = c.CustomerID  
         INNER  JOIN Person.Person AS per 
                       ON c.PersonID = per.BusinessEntityID 
WHERE    LineTotal > 25000

SQL Server parse and compile time:    
   CPU time = 0 ms, elapsed time = 0 ms. 

SQL Server Execution Times: 
   CPU time = 452 ms,  elapsed time = 458 ms.
复制代码

上面的查询使用AdventureWorks2008数据库,字段LineTotal上没有索引,会导致SalesOrderDetail全表扫描。然后创建如下索引后,改善很明显:

复制代码
CREATENONCLUSTEREDINDEX
idx_SalesOrde 
ON
Sales.SalesOrderDetail (LineTotal)
SQL Server parse and compile time:  
   CPU time = 0 ms, elapsed time = 0 ms. 

SQL Server Execution Times: 
   CPU time = 0 ms,  elapsed time = 8 ms.
复制代码

 

过期的统计信息

     查询优化器使用统计信息计算各种查询操作的基数(开销)。查询操作的成本(cost)又决定了查询计划的成本。过期的统计信息会导致生成非最优的查询计划,

如预估成本很低,但实际成本很高的计划。

最常见就是预估行数很少,并选择了那些适合少量数据的操作(如嵌套循环,LookUp),但当实际执行时要处理的行数却很多,查询效率就变得很低。

可以通过SSMS或者set statistics profile on为索引查找和扫描操作,返回实际行数与预估行数做比较。如果两者差异较大,就很有可能统计信息过期了。

过期时,可以使用update statistics tableName更新表上所有的统计信息,update statistics tableName statisticsName更新指定统计信息。

为了防止统计信息过期的问题,有如下三种方法:

   a. 开启数据库的Auto_Update_Statistics选项或者用定时作业更新全库的统计信息。

   b. 如果某些索引的自动更新统计信息被禁用,则需要指定STATISTICS_NORECOMPUTE=OFF重建索引开启。

   c. 对于某些经常因为统计信息过期而导致性能问题的统计信息,可以创建定时作业频繁地更新它们。

 

非SAGR谓词

SAGR=Search Agrument.简单说就是能够使用索引查找的谓词。列应该直接与表达式进行比较则符合SAGR,如WHERE  SomeFunction(Column) = @Value就符合,    

WHERE Column = SomeOtherFunction(@Value) 则符合。注意LIKE和BETWEEN也是SAGR谓词。

非SAGR会导致表或者索引扫描,它的影响跟缺失索引类似。使得CPU处理大量非必需的数据行。下面查询会导致索引扫描:

复制代码
SELECT  soh .SalesOrderID , 
        OrderDate , 
        DueDate , 
        ShipDate  , 
        Status  , 
        SubTotal  , 
        TaxAmt  , 
        Freight , 
        TotalDue 
FROM    Sales.SalesOrderheader  AS soh 
         INNER  JOIN Sales.SalesOrderDetail  AS sod   
                     ON soh.SalesOrderID = sod.SalesOrderID  
WHERE     CONVERT(VARCHAR(10), sod.ModifiedDate , 101) = '01/01/2010'
复制代码

改写成如下则会使用索引查找:

复制代码
SELECT  soh .SalesOrderID , 
        OrderDate , 
        DueDate , 
        ShipDate  , 
        Status  , 
        SubTotal  , 
        TaxAmt  , 
        Freight , 
        TotalDue 
FROM    Sales.SalesOrderheader  AS soh 
         INNER  JOIN Sales.SalesOrderDetail  AS sod  ON soh.SalesOrderID = sod.SalesOrderID  
WHERE    sod.ModifiedDate >= '2010/01/01'  
         AND  sod.ModifiedDate < '2010/01/02'
复制代码

UPPER,LOWER,LTRIM,RTRIM,ISNULL这些经常会被滥用,甚至用于WHERE和JOIN条件中。

在不区分大小写排序规则中,大小写被视为相等的,像UPPER,LOWER这种拖累性能的函数就不必要用了。

SQL中字符串比较会忽略末尾空格,所以RTRIM也没必要用。

下面两个过滤条件,前者,字段NULL值转换成0从而被排除;后者中,其实NULL值与任何值比较操作都不会返回TURE,而被排除。

NULL值只在IS NULL或者IS NOT NULL检查时才可能返回TRUE。所以是等效的,但后者才能使用索引查找。

WHERE  ISNULL(SomeCol,0) > 0
WHERE  SomeCol > 0

 

隐式转换

     隐式转换发生在比较两个不同数据类型时。SQL不能对不同类型数据进行比较,所以查询优化器会在比较操作前把低优先级的数据类型转换成高优先级的数据类型再比较。

这跟非SARG谓词一样,将不能使用Index Seek,从而处理很多不必要的数据行,增加CPU开销。最常见例子是使用NVARCHAR类型的参数与VARCHAR类型的列进行比较。如:

 
复制代码
SELECTp .FirstName , p.LastName , c.AccountNumber 
FROM
Sales.Customer ASc 
INNER JOINPerson.Person AS p 
ON c.PersonID = p.BusinessEntityID 
 WHERE AccountNumber = N'AW00029594'
复制代码
上面的查询导致一个非聚集索引扫描,在Filter操作中会看有一个COVERT_IMPLICIT。

为了避免隐式转换:

    1. JOIN的列,数据类型尽量相同

    2. 与列比较时,任何参数,变量和常量的类型要和列的类型相同

    3. 当参数,变量或常量的类型与要比较的列不同时,斟酌地使用类型转换函数,使其与列类型相同

    4. 有些数据访问组件和开发框架会把字符串类型默认地设置为NVARCHAR

 

参数探测(Parameter Sniffing)

      参数探测是SQL Server为存储过程,函数和参数化查询创建查询计划时用到的处理方式。当首次编译查询计划时,SQL Server会检测或者探测输入参数的值并结合统计信

息,预估受影响的行数,

并以之估算查询计划成本。当根据传入的参数值创建查询计划,得到的受影响行数不是典型的情况时,就产生问题了。参数探测只出现在编译和重编译时,之后的存储过程,函数和

参数化查询,

会重用此查询计划。最初编译时只有输入参数的值会被探测到,本地变量是没有值的。如果批处理中的语句被重编译,则参数和变量将会被赋值并探测到。示例如下:

复制代码
CREATEPROCEDUREuser_GetCustomerShipDates 
( @ShipDateStart DATETIME
, @ShipDateEnd DATETIME
) 
AS
SELECT CustomerID , SalesOrderNumber 
FROM Sales.SalesOrderHeader 
WHERE ShipDate BETWEEN @ShipDateStart AND @ShipDateEnd 
GO
复制代码
Sales.SalesOrderHeader表的ShipDate字段范围是2004-08-07~2011-08-07,并创建非聚集索引: 
复制代码
CREATENONCLUSTEREDINDEX IDX_ShipDate_ASC 
ON Sales.SalesOrderHeader (ShipDate ) 
GO
首先我们执行两次SP,并用DBCC FREEPROCCACHE在运行前清空计划缓存: 
DBCC FREEPROCCACHE 
EXEC user_GetCustomerShipDates '2001/07/08', '2004/01/01' 
EXEC user_GetCustomerShipDates '2001/07/10', '2001/07/20'
复制代码
查询计划如图: 
image
查询并没有使用ShipDate列非聚集索引,因为它不是一个覆盖索引,并且被执行时,查询优化器根据参数值结合统计信息预估的行数很多,使用IndexSeek和LookUp的组合成本
太高。再观察STATISTICS IO&TIME:
复制代码
==FIRST EXECUTION (LARGE DATE RANGE)===  

(Table 'SalesOrderHeader'. Scan count 1, logical reads 686, physical reads 0.  

 SQL Server Execution Times: 
   CPU time = 16 ms,  elapsed time = 197 ms. 

 SQL Server Execution Times: 
   CPU time = 16 ms,  elapsed time = 197 ms. 

==SECOND EXECUTION (SMALL DATE RANGE)=== 

Table 'SalesOrderHeader'. Scan count 1, logical reads 686, physical reads 0. 

 SQL Server Execution Times: 
   CPU time = 15 ms,  elapsed time = 5 ms. 

 SQL Server Execution Times: 
   CPU time = 15 ms,  elapsed time = 5 ms.
复制代码
两者的纯CPU时间和IO是基本一样,因为前者需要处理的数据量多很多,所以CPU消耗时间长一些。接下来,调换两个执行SP的顺序,再执行:
复制代码
DBCC FREEPROCCACHE 
EXEC user_GetCustomerShipDates '2001/07/10', '2001/07/20' 
EXEC user_GetCustomerShipDates '2001/07/08', '2004/01/01'
复制代码
image
复制代码
==FIRST EXECUTION (SMALL DATE RANGE)===  

Table 'SalesOrderHeader'. Scan count 1, logica
ahead reads 0, lob logical reads 0, lob physic

 SQL Server Execution Times: 
   CPU time = 0 ms,  elapsed time = 0 ms.  

==SECOND EXECUTION (LARGE DATE RANGE)=== 

Table 'SalesOrderHeader'. Scan count 1, logica

 SQL Server Execution Times: 
   CPU time = 47 ms,  elapsed time = 182 ms.
复制代码
这次两者性能差距就很明显了。参数探测导致优化器采用了适合少量数据的KeyLookUp操作,而第二次查询重用了此查询计划,但是实际它需要处理大量数据,
这时KeyLookUp就导致了明显的性能问题,需要额外的IO和CPU资源。 
根据具体的环境和SQL Server版本,有多种处理参数探测的方法:
1. 跟踪标志4136
      此跟踪标志使得SQLServer实例不再使用参数探测,而是使用列平均重复个数(=总行数/列的非重复值个数)来估算受影响行数。 这样的估算值是不精确的。
启用此标志将会使得那些正确的参数探测的情况,变得不准确,带来负面影响。所以应该做为最后的手段。
适用于SQL Server 2008 SP1 CU7,SQL Server 2008 R2 CU2,SQL Server 2005 in SP3 CU9。 
2. 使用OPTIMIZE FOR查询提示 SQLServer 2005及后续版本中,可以为查询优化器编译查询计划时指定参数的值。如:
复制代码
CREATE PROCEDURE user_GetCustomerShipDates 
    ( 
      @ShipDateStart DATETIME  , 
      @ShipDateEnd DATETIME  
    ) 
AS   
    SELECT  CustomerID , 
            SalesOrderNumber 
    FROM    Sales.SalesOrderHeader 
    WHERE    ShipDate  BETWEEN @ShipDateStart AND  @ShipDateEnd 
    OPTION   ( OPTIMIZE  FOR ( @ShipDateStart = '2001/07/08' , 
                              @ShipDateEnd = '2004/01/01'  ) ) 
GO
复制代码
在2008中还能OPTIMIZE FOR UNKNOWN使得优化器不用参数探测,这个跟T-4136一样,只不过是语句级。
        
3. 重编译选项   

         在创建存储可以指定WITH RECOMPILE重编译选项。指定后SP每次执行时会基于当前参数值重新编译,同时也不缓存执行计划。但是这样会增加执行处理时间。

复制代码
CREATE PROCEDURE user_GetCustomerShipDates 
                   ( 
                     @ShipDateStart DATETIME  , 
                     @ShipDateEnd DATETIME  
                   ) 
                   WITH RECOMPILE 
                   AS   
                   SELECT  CustomerID ,SalesOrderNumber 
                   FROM    Sales.SalesOrderHeader 
                   WHERE    ShipDate  BETWEEN @ShipDateStart AND  @ShipDateEnd
复制代码

   当SP中的多个语句,只是某个语句会产生参数探测问题,则可以对这个语句使用OPTION(RECOMPILE)查询提示。这样每次执行时只会对这个语句重编译,

    而不像WITH RECOMPILE对整个SP重编译。如果可能尽量使用查询提示,减少重编译的影响范围和开销。

复制代码
CREATE PROCEDURE user_GetCustomerShipDates 
             ( 
               @ShipDateStart DATETIME  , 
               @ShipDateEnd DATETIME  
             ) 
             AS   
              SELECT  CustomerID , 
                     SalesOrderNumber 
              FROM    Sales.SalesOrderHeader 
              WHERE    ShipDate  BETWEEN @ShipDateStart AND  @ShipDateEnd 
              OPTION ( RECOMPILE )
复制代码
 
即席非参数化查询
    即席查询不能重用执行计划,每次执行时都会被编译,消耗大量资源(特别是CPU)。像下面的查询,每次因为WHERE条件中参数值不同而产生不同的执行计划。
    虽然SQL Server有简单参数化(Simple Parameterization)的技术,但是此语句相对”太复杂”了。
复制代码
SELECT  soh .SalesOrderNumber  , 
            sod.ProductID 
    FROM    Sales.SalesOrderHeader  AS soh 
    INNER  JOIN Sales.SalesOrderDetail  AS sod 
                ON soh.SalesOrderID = sod.SalesOrderID  
    WHERE    soh.SalesOrderNumber  = 'SO43662'
复制代码
    非参数化查询主要有两方面的影响:
        1. 即席查询产生的一次性的查询计划会填满计划缓存。由此带来的内存压力,会让那些本可以重用的计划迫于内存压力而被清除掉等等。
        2. 编译这些一次性的查询计划浪费了大量的CPU资源。
    可以用下面的计数器来判断即席非参数化查询的影响程度: 

SQLServer: SQL Statistics: SQL Compilations/Sec
SQLServer: SQL Statistics: Auto-Param Attempts/Sec
SQLServer: SQL Statistics: Failed Auto-Param/Sec

解决的方法有:

1. 修改应用程序代码,使发送到SQL Server语句尽量被参数化。

2. 在SQL Server 2005及以上版本中,能在数据库级别设定强制参数化。但可能会带来类型参数探测一样的问题。

复制代码
ALTER  DATABASE  AdventureWorks SET  PARAMETERIZATION FORCED
复制代码
 3. SQL Server 2008及以上版本中,启用实例级别的optimize for  ad hoc  workloads。
        启用后当即席查询第一次执行时只保存查询计划的一个“存根”,第二次执行时则缓存执行计划。“存根”使用很少的内存,
        这样就减少了那些本可以重用的执行计划,因内存压力而被清除掉的机率。
复制代码
EXEC sp_configure  'show advanced options',1 
              RECONFIGURE 
              EXEC sp_configure  'optimize for ad hoc workloads',1 
              RECONFIGURE
复制代码
不恰当的并行
   并行查询是把一个查询的工作分解成多个线程执行,每一个线程使用单独的计划程序。查询并行发生在操作符(Operator)级别。
查询优化器在编译执行计划时总是会让其尽可能的快。如果执行计划的预估成本连续超过cost threshold of prillelism,同时SQL Server可用
CPU个数多于1个,并且max degree of prallelism为0或大于1,则产生的执行计划将会包括并行。
并行查询通过水平分割输入数据,然后分布到多个逻辑CPU上同时执行,从而减少执行时间。对于数据仓库和报表系统会有好处,对于OLTP系统
则并行会占用过多的CPU资源,而其它的请求不得不等待CPU资源。
SQL Server有两个控制并行执行的sp_configure选项:
   cost threshold of prillelism:控制优化器为查询使用并行执行的阀值
   max degree of prallelism:避免单个查询用完所有可用的处理器内核
 cost threshold of prallelism的默认值为5秒。在较大的数据库上,默认阀值可能太低了,会导致并行执行的资源争用。
 可以通过下面的查询获取存于计划缓存中的并行执行计划,做为调整cost threshold of prillelism的重要参考依据:
复制代码
SET  TRANSACTION ISOLATION LEVEL  READ UNCOMMITTED ;  

WITH XMLNAMESPACES 
    (DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan')   
SELECT query_plan  AS CompleteQueryPlan , 
        n.value ('(@StatementText)[1]', 'VARCHAR(4000)' ) AS StatementText  , 
        n.value ('(@StatementOptmLevel)[1]', 'VARCHAR(25)') 
                  AS StatementOptimizationLevel , 
        n.value ('(@StatementSubTreeCost)[1]', 'VARCHAR(128)') 
                   AS StatementSubTreeCost  , 
        n.query ('.' ) AS ParallelSubTreeXML  , 
        ecp.usecounts  , 
        ecp.size_in_bytes 
FROM    sys .dm_exec_cached_plans  AS ecp 
         CROSS  APPLY  sys .dm_exec_query_plan(plan_handle) AS eqp 
         CROSS  APPLY  query_plan.nodes  
                ('/ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple') 
         AS qn  ( n  ) 
WHERE    n.query ('.' ).exist ('//RelOp[@PhysicalOp="Parallelism"]' ) = 1
复制代码
 
并行中使用到处理器数是取自后面三者中的最小值:max degree of prallelis的值,可用的处理器数和MAXDOP查询提示(会覆盖max degree of prallelis指定的值)。
合适的max degree of prallelis值取决于工作负载类型和硬件资源支撑并行开销的能力。很多砖家推荐将其设定为1,前提是你的系统是真正的单独的OLTP系统,
只有大量的并发的小事务。对于NUMA和SMP系统的设定是不同的。SQL Server 2008及以上版本利用resource governor能将max degree of prallelis绑定到特定的查询组。
 
当系统出现并行性能问题时,通常会CXPACKET等待会比较明显,其实它很冤,它只是个表面现象。根本原因还是要查看产生CXPACKET等待的子线程的等待类型。
如果伴随着如IO_COMPLETION,ASYNC_IO_COMPLETION,PAGEIOLATCH_*的等待,则要提高IO性能;
如果伴随着LATCH_*  and SOS_SCHEDULER_YIELD,则表示并行本身导致了性能问题,如果此时还有ACCESS_METHODS_DATASET_PARENT等待,则执行的并行度是根本原因。
出现这些问题时首先应该优化并行执行的语句,其次才是结合max degree of prallelis和cost threshold of prillelism两者进行限制,再次是提升硬件。
在硬件暂时无法提升时,只能对并行做一定限制,做折中和权衡考量。
 
在SQL Server 2005,有个关于TokenAndPermUserStore的CPU问题。当数据库用户很多,adhoc和动态查询很多且非AWE内存空间很多时,

可能会出现CMEMTHREAD大量等待和TokenAndPermUserStore使用过量并持续增长。微软已经推出的解决方案http://support.microsoft.com/kb/927396
长期的解决方案是修改程序架构,尽量减少可能导致此问题的adhoc和动态查询的使用。
短期解决方案是:
   1. 给应用程序账户提升为sysadmin,从而规避权限检查而极大的减少TokenAndPermUserStore的缓存使用量。这是有安全风险的
   2. 使用DBCC FREESYSTEMCACHE ('TokenAndPermUserStore'),定期清理这一部分缓存。
   3. SQL Server 2005 SP2及以上版本,可以使用Trace Flag 4618&4610.4610限制缓存条目为1024,两者都启用则限制缓存条目为8192.
   4. SQL Server 2005 SP3及以上版本,使用Trace Flag 4621,可以设定缓存配额。 http://support.microsoft.com/kb/959823。
   5. SQL Server 2008有access check cache bucket count & access check cache quota两个sp_configure项,
      用于设置TokenAndPermUserStore的hash bucket数量和缓存条目数。
 
关于超线程和BIOS节能控制选项
   很多砖家推荐SQL Server服务器不宜开启超线程,根据作者的研究,这种推荐做法在过去是对的,现在不一定是对的。
在过去,超线出来的CPU会一起共享板载缓存,而这个缓存是KB量级的。而且windows 2000本身不支持超线程,“超”出来的它会认为是物理CPU。“CPU”一多就会造成缓存命中率低下,进而影响性能。

而很多DBA管理的OLTP&DSS的混合环境,那么超线程对于那些DSS型查询的提升,在混合环境中很不明显,甚至有时会导致需要迅速响应OLTP弄查询等待。
现在,硬件和软件进步了,现在板载缓存量级都是MB级的了,CPU缓存命中率不再是问题。而windows 2003也支持超线程了。而且现在OLTP,OLAP,DW等系统一般会隔离使用。
当然是否开启还是需要经过测试才能最终决定。
 
绿色节能现在也是硬件和服务器一种标准了,自动降低系统中某些暂时未用到的硬件能耗和CPU频率。BioS中可以设定为硬件自己控制或者OS控制。
windows 2008&r2默认设定电源计划为“平衡”,以允许其切换到节能模式。有时在windows 2008 or R2的新服务器升级系统一段时间后,性能下降明显,这就是电源管理造成的CPU降频导致的。
windows的性能计数器 % Processor Usage 是已使用CPU频率除以可用CPU频率得到的。如果CPU被降频了,那么这个计算器会较高,会让人误会成工作负载很高。
可以使用CPU-Z来检测CPU的状态。
建议将windows的电源计划调定为“高性能”,并且检查BIOS的电源控制选项,设定为OS Control.
 
总结:
   1. SQL SERVER CPU调整的地方很少,很多时候还是因为语句性能低下导致CPU使用过高。
   2. 解决参数嗅探问题,还有拼动态语,使用plan_guide等方法。

————————————-

作者:Joe.TJ

Joe’s Blog:http://www.cnblogs.com/Joe-T/

[转载]C# 自动提交到百度ping服务 - javaoraspx - 博客园

mikel阅读(1110)

[转载]C# 自动提交到百度ping服务 – javaoraspx – 博客园.

今天无意之间看到百度站长中有这个ping服务(孤陋寡闻呀)….

那什么什么是Ping服务

ping是基于XML_RPC标准协议的更新通告服务,用于博客把内容更新快速通知给百度,以便百度及时进行抓取和更新。

看着是简单的http post 提交.但是自己用 WebRequest 模拟时.死活返回操作超时.简直无语.

下面百度ping 服务的例子(注意红色部分.现在http的版本是1.1了.就是这个细节导致无法提交),顺便说说Fiddler 这个工具确实很好用.

复制代码
Ping请求包的例子 http://zhanzhang.baidu.com/tools/ping

weblogUpdates.extendedPing xml-rpc请求举例:
POST /ping/RPC2 HTTP/1.0
User-Agent: request
Host: ping.baidu.com
Content-Type: text/xml
Content-Length: 511

<?xml version="1.0" encoding="UTF-8"?><methodCall>
    <methodName>weblogUpdates.extendedPing</methodName>
    <params>
        <param>
            <value><string>百度的空间</string></value>
        </param>
        <param>
            <value><string>http://hi.baidu.com/baidu/</string></value>
        </param>
        <param>
            <value><string>http://baidu.com/blog/example.html</string></value>
        </param>
        <param>
            <value><string>http://hi.baidu.com/baidu/rss</string></value>
        </param>
    </params>
</methodCall>
复制代码

下面放出我自己的简单例子(已经通过测试了)

复制代码
      public void postToPing( )
        {
            try
            { 
                string posturl = "http://ping.baidu.com/ping/RPC2"; //post 提交地址
                string refurl = "http://www.weletgo.com/"; //这里可以随便填写.
                string content_type = "text/xml";        //提交类型.这里一定要text/xml
                string postdt = postdata();              //提交数据
                string str = baiduping(posturl, postdt, content_type, refurl, false, Encoding.UTF8); 
                Stream sm = new System.IO.MemoryStream(Encoding.UTF8.GetBytes(str)); //下面这里检测提交是否成功
                XElement xle = XElement.Load(sm);
                var query = xle.Descendants("int");
                if (query.Count() > 0)
                {
                    string _val = query.ElementAtOrDefault(0).Value;
                    if (_val == "1")
                    {
                        Console.WriteLine("失败");
                    }
                    else
                    {
                        Console.WriteLine("成功");
                    }
                } 
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);

               // log.Error(ex.Message);
            }
        }
        private string postdata()
        { 
            //注意xml拼接的时候,xml的第一行的开头必须不能有空格等 //下面直接是引用百度的例子
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?><methodCall>");
            sb.AppendLine(" <methodName>weblogUpdates.extendedPing</methodName>");
            sb.AppendLine("<params>");
            sb.AppendLine(" <param> ");
            sb.AppendLine("<value><string>百度的空间</string></value>");
            sb.AppendLine(" </param> ");
            sb.AppendLine(" <param>");
            sb.AppendLine("<value><string>http://hi.baidu.com/baidu/</string></value>");
            sb.AppendLine("</param>");
            sb.AppendLine("<param>");
            sb.AppendLine(" <value><string>http://baidu.com/blog/example.html</string></value>");
            sb.AppendLine(" </param>");
            sb.AppendLine(" <param> ");
            sb.AppendLine("<value><string>http://hi.baidu.com/baidu/rss</string></value>");
            sb.AppendLine("</param> ");
            sb.AppendLine("</params>");
            sb.AppendLine("</methodCall>");
            return sb.ToString().Trim();
        }

        private string baiduping(string targetURL, string formData, string contentType, string referer, bool allowAutoRedirect, Encoding ed)
        {
            ASCIIEncoding encoding = new ASCIIEncoding(); 
            byte[] data = encoding.GetBytes(formData); 
            //请求目标网页
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(targetURL);
            request.Method = "POST";    //使用post方式发送数据 
            request.UserAgent = "request";
            request.Referer = referer;
            request.ProtocolVersion = new Version("1.0");  //注意这里这个版本好.一定要设置.现在默认提交是1.1了.否则会一直提示504
            request.ContentType = contentType == "" ? "application/x-www-form-urlencoded" : contentType;
            request.Timeout = 1000 * 10;
            request.ContentLength = data.Length;
            Stream newStream = request.GetRequestStream();
            newStream.Write(data, 0, data.Length);
            newStream.Close();

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            Stream stream = response.GetResponseStream(); 
            string html = new StreamReader(stream, ed).ReadToEnd();
            return html;  
        }
复制代码

代码部分就是这么简单.自动提交当然要在数据添加这里调用posttoping 这方法.现在有很多提供插件.只需配置一下就行了.

同步发布到http://www.weletgo.com/  弄这个网站的最初原因是逼自己学习mvc3. 现在终于会点皮毛了,很久没有弄web这方面了.

资源方面就是写个程序.在后台自动抓取别人的东西,没啥技术含量

[转载]Python:Python学习总结 - 幸福框架 - 博客园

mikel阅读(787)

[转载]Python:Python学习总结 – 幸福框架 – 博客园.

背景

PHP的$和->让人输入的手疼(PHP确实非常简洁和强大,适合WEB编程),Ruby的#、@、@@也好不到哪里(OO人员最该学习的一门语言)。

Python应该是写起来最舒服的动态语言了,一下是一些读书笔记,最后会介绍一下高级的用法:Mixin、Open Class、Meta Programming和AOP

文中有些地方是用2.7开发的,如果您安装的是3.x,有几点需要注意:

  • print “xxx” 要换成 print(“xxx”)
  • __metaclass__ = type 删除掉。

类型和表达式部分

你好,世界!

复制代码
1 # coding=utf-8
2 
3 print "你好,世界。"
复制代码

 乘方

复制代码
1 print 2**10
复制代码

变量

复制代码
1 var = 1
2 print var
3 
4 var  = "段光伟"
5 print var
复制代码

注:这里的var = xxxx不叫变量赋值,而叫变量绑定,python维护了一个符号表(变量名)以及符合对应的值,这个对应关系就叫做绑定,一个符号可以绑定任意类型的值。

获取用户输入

复制代码
1 #获取用户输入
2 x = input("x:")
3 y = input("y:")
4 
5 print x*y
复制代码

注:input接受的是Python代码,输入中可以访问当前执行环境中的变量,如果想获取原始输入需要使用 raw_input。

函数定义

复制代码
1 def say_b():
2     print "b"
复制代码

强类型

JavaScript和Php是弱类型的,Python和Ruby是强类型的。弱类型允许不安全的类型转换,强类型则不允许。

复制代码
1 #1 + “1” 这行代码在Python中会报错。
2 print 1 + int("1")
3 print str(1) + "1"
复制代码

 字符串

复制代码
1 #字符串
2 print ''''    段
3 4 '''
5 print r'C:\log.txt'
6 print 'C:\\log.txt'
复制代码

序列

这里先介绍三种序列:列表、元祖和字符串。

序列通用操作

复制代码
 1 seq = "0123456789"
 2 print seq[0] #从0开始编码。
 3 print seq[-1] #支持倒着数数,-1代表倒数第一。
 4 print seq[1:5] #支持分片操作,seq[start:end],start会包含在结果中,end不会包含在结果中。
 5 print seq[7:] #seq[start:end]中的end可以省略。
 6 print seq[-3:] #分片也支持负数。
 7 print seq[:3] #seq[start:end]中的start也可以省略。
 8 print seq[:] #全部省略会复制整个序列。
 9 print seq[::2] #支持步长。
10 print seq[::-2] #支持负步长。
11 print seq[9:1:-1] #支持负步长。
12 print [1, 2, 3] + [4, 5, 6] # 序列支持相加,这解释了为啥字符串可以相加。
13 print [1, 2, 3] * 3 #序列支持相乘,这解释了为啥字符串可以相称。
14 print [None] * 10 #生成一个空序列。
15 print 1 in [1, 2, 3] #成员判断。
复制代码

可变的列表

复制代码
 1 data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
 2 
 3 data[0] = "a" #修改元素。
 4 print data
 5 data[0] = 0
 6 
 7 del data[10] #删除元素。
 8 print data
 9 
10 del data[8:] #分片删除。
11 print data
12 
13 data[8:] = [8, 9, 10] #分片赋值
14 print data
复制代码

不可变的元祖

复制代码
1 print (1, 2) #元祖以小括号形式声明。
2 print (1,) #一个元素的元祖。
复制代码

字符串格式化

复制代码
1 print "% 10s" % "----"
2 
3 print '''
4 %(title)s
5 %(body)s
6 ''' % {"title": "标题", "body": "内容"}
复制代码

字典

复制代码
1 print {"title": "title", "body": "body"}
2 print dict(title = "title", body = "body")
3 print dict([("title", "title"), ("body", "body")])
复制代码
复制代码
1 dic = {"title": "title", "body": "body"};
2 print dic["title"]
3 del dic["title"]
4 print dic
复制代码

print 语句

复制代码
1 print 'a', 'b' #print可以接受多个参数,参数的输出之间以空格相隔。
2 print 'a', #如果逗号之后没有参数,则不会换行。
3 print 'b'
复制代码

序列解包

复制代码
1 x, y, z = 1, 2, 3
2 print x, y, z
3 (x, y, z) = (1, 2, 3)
4 print x, y, z
5 (x, y, z) = [1, 2, 3]
6 print x, y, z
复制代码

bool值

复制代码
 1 #下面的输入全部返回False。
 2 print(bool(None))
 3 print(bool(()))
 4 print(bool([]))
 5 print(bool({}))
 6 print(bool(""))
 7 print(bool(0))
 8 
 9 #虽然这些值在条件运算中会当做False,但是本身不等于False。
10 print(True and "")
11 print(not "")
12 print(False == "")
13 print(False == 0) #0除外,bool类型的内部表示就是int类型。
复制代码

bool运算

复制代码
1 print(0 < 1 < 10)
2 print(0 < 1 and 1 < 10)
3 print(not(0 > 1 > 10))
4 print(not(0 > 1 or 1 > 10))
复制代码

语句块

:开始语句快,缩进的所有内容都是一个语句块。

复制代码
1 if(10 > 1):
2     print("10 > 1")
3 else:
4     print("不可能发生")
复制代码

三元运算符

复制代码
1 print("10 > 1" if 10 > 1 else "不可能发生")
复制代码

相等比较

复制代码
1 #== 和 is的差别,==比较的是内容,is比较的是引用。
2 x = [1, 2, 3]
3 y = x
4 z = [1, 2, 3]
5 print(x == y)
6 print(x == z)
7 print(x is y)
8 print(x is z)
复制代码

循环

复制代码
 1 #for循环类似C#的foreach,注意for后面是没有括号的,python真是能简洁就尽量简洁。
 2 for x in range(1, 10):
 3     print(x)
 4 
 5 for key in {"x":"xxx"}:
 6     print(key)
 7 
 8 for key, value in {"x":"xxx"}.items():
 9     print(key, value)
10 
11 for x, y, z in [["a", 1, "A"],["b", 2, "B"]]:
12     print(x, y, z)
复制代码
复制代码
 1 #带索引的遍历
 2 for index, value in enumerate(range(0, 10)):
 3     print(index, value)
 4 
 5 #好用的zip方法
 6 for x, y in zip(range(1, 10), range(1, 10)):
 7     print(x, y)
 8 
 9 #循环中的的else子句
10 from math import sqrt
11 for item in range(99, 1, -1):
12     root = sqrt(item)
13     if(root == int(root)):
14         print(item)
15         break
16 else:
17     print("没有执行break语句。")
复制代码

pass、exec和eval

复制代码
1 #pass、exec、eval
2 if(1 == 1):
3     pass
4 
5 exec('print(x)', {"x": "abc"})
6 print(eval('x*2', {"x": 5}))
复制代码

函数部分

形参和实参之间是按值传递的,当然有些类型的值是引用(对象、列表和字典等)。

复制代码
 1 # 基本函数定义。
 2 def func():
 3     print("func")
 4 
 5 func()
 6 
 7 # 带返回值的函数。
 8 def func_with_return():
 9     return ("func_with_return")
10 
11 print(func_with_return())
12 
13 # 带多个返回值的函数。
14 def func_with_muti_return():
15     return ("func_with_muti_return", "func_with_muti_return")
16 
17 print(func_with_muti_return())
18 
19 # 位置参数
20 def func_with_parameters(x, y):
21     print(x, y)
22 
23 func_with_parameters(1, 2)
24 
25 # 收集多余的位置参数
26 def func_with_collection_rest_parameters(x, y, *rest):
27     print(x, y)
28     print(rest)
29 
30 func_with_collection_rest_parameters(1, 2, 3, 4, 5)
31 
32 #命名参数
33 def func_with_named_parameters(x, y, z):
34     print(x, y, z)
35 
36 func_with_named_parameters(z = 1, y = 2, x = 3)
37 
38 #默认值参数
39 def func_with_default_value_parameters(x, y, z = 3):
40     print(x, y, z)
41 
42 func_with_default_value_parameters(y = 2, x = 1)
43 
44 #收集命名参数
45 def func_with_collection_rest_naned_parameters(*args, **named_agrs):
46     print(args)
47     print(named_agrs)
48 
49 func_with_collection_rest_naned_parameters(1, 2, 3, x = 4, y = 5, z = 6)
50 
51 #集合扁平化
52 func_with_collection_rest_naned_parameters([1, 2, 3], {"x": 4, "y": 4, "z": 6}) #这会导致args[0]指向第一个实参,args[1]指向第二个实参。
53 func_with_collection_rest_naned_parameters(*[1, 2, 3], **{"x": 4, "y": 4, "z": 6}) #这里的执行相当于func_with_collection_rest_naned_parameters(1, 2, 3, x = 4, y = 5, z = 6)。
复制代码

作用域

复制代码
 1 # coding=utf-8
 2 
 3 # 只有函数执行才会开启一个作用域。
 4 if(2 > 1):
 5     x = 1
 6 
 7 print(x) # 会输出1。
 8 
 9 
10 # 使用vars()函数可以访问当前作用域包含的变量。
11 x = 1
12 print(vars()["x"])
13 
14 # 使用globals()函数可以访问全局作用域。
15 x = 1
16 
17 def func():
18     print(globals()["x"])
19 
20 func()
21 
22 # 使用locals()函数可以访问局部作用域。
23 def func():
24     x = 2
25     print(locals()["x"])
26 
27 func()
28 
29 # 每个函数定义时都会记住所在的作用域。
30 # 函数执行的时候会开启一个新的作用域,函数内变量访问的规则是:先访问当前作用域,如果没有就访问函数定义时的作用域,递归直到全局作用域。
31 x = 1
32 
33 def func():
34     y = 2
35     print(x, y) # 输出1 2
36 
37 func()
38 
39 
40 # 变量赋值始终访问的是当前作用域。
41 x = 1
42 
43 def func():
44     x = 2
45     y = 2
46     print(x, y) # 输出2 2
47 
48 func()
49 print(x) #输出 1
50 
51 # 局部变量会覆盖隐藏全局变量,想访问全局变量可以采用global关键字或globals()函数。
52 x = 1
53 
54 def func():
55     global x
56     x = 2
57     y = 2
58     print(x, y) # 输出2 2
59 
60 func()
61 print(x) #输出 2
复制代码
复制代码
 1 # python支持闭包
 2 def func(x):
 3     def inner_func(y):
 4         print(x + y)
 5 
 6     return inner_func
 7 
 8 inner_func = func(10)
 9 inner_func(1)
10 inner_func(2)
复制代码
复制代码
1 #函数作为对象
2 def func(fn, arg):
3     fn(arg)
4 
5 func(print, "hello")
6 func(lambda arg : print(arg), "hello")
复制代码

模块

几个模块相关的规则:

  • 一个文件代表一个模块。
  •  可以用import module导入模块,也可以用form module import member导入模块的成员。
  • 如果导入的是module,必须使用module.member进行访问;如果导入的member,可以直接访问member。
  • 导入的module或member都会变成当前module的member。

b.py

复制代码
1 # coding=utf-8
2 
3 print __name__
4 
5 def say_b():
6     print "b"
复制代码

a.py

复制代码
1 # coding=utf-8
2 
3 import b
4 from b import *
5 
6 print __name__
7 
8 def say_a():
9     print "a"
复制代码

test.py

复制代码
1 # coding=utf-8
2 
3 import a
4 
5 print __name__
6 
7 a.say_a();
8 a.say_b();
9 a.b.say_b()
复制代码

输出

复制代码
1 b
2 a
3 __main__
4 a
5 b
6 b
复制代码

异常管理

复制代码
 1 # coding=utf-8
 2 
 3 # 自定义异常
 4 class HappyException(Exception):
 5     pass
 6 
 7 # 引发和捕获异常
 8 try:
 9     raise HappyException
10 except:
11     print("HappyException")
12 
13 try:
14     raise HappyException()
15 except:
16     print("HappyException")
17 
18 # 捕获多种异常
19 try:
20     raise HappyException
21 except (HappyException, TypeError):
22     print("HappyException")
23 
24 # 重新引发异常
25 try:
26     try:
27         raise HappyException
28     except (HappyException, TypeError):
29         raise
30 except:
31     print("HappyException")
32 
33 #访问异常实例
34 try:
35     raise HappyException("都是我的错")
36 except (HappyException, TypeError), e:
37     print(e)
38 
39 #按类型捕获
40 try:
41     raise HappyException
42 except HappyException:
43     print("HappyException")
44 except TypeError:
45     print("TypeError")
46 
47 #全面捕获
48 try:
49     raise HappyException
50 except:
51     print("HappyException")
52 
53 #没有异常的else
54 try:
55     pass
56 except:
57     print("HappyException")
58 else:
59     print("没有异常")
60 
61 #总会执行的final
62 try:
63     pass
64 except:
65     print("HappyException")
66 else:
67     print("没有异常")
68 finally:
69     print("总会执行")
复制代码

面向对象

先上一张图

几个规则:

  1. 一切都是对象,python中一切都是对象,每个对象都包含一个__class__属性以标记其所属类型。
  2. 每个对象(记得一切都是对象啊)都包含一个__dict__属性以存储所有属性和方法。
  3. 每个类型都包含一个__bases__属性以标记其父类。
  4. 属性和方法的访问规则:依次搜索instance、子类、父类、父类的父类、直到object的__dict__,如果找到就返回。
  5. 属性和方法的设置规则:直接设置instance.__dict__。
  6. 以上属性和方法访问或设置规则没有考虑“魔法方法”,下文会解释。

 示例

复制代码
 1 # coding=utf-8
 2 
 3 __metaclass__ = type
 4 
 5 # 类型定义
 6 # 实例方法必的第一个参数代表类型实例,类似其他语言的this。
 7 class Animal:
 8     name = "未知" # 属性定义。
 9 
10     def __init__(self, name): #构造方法定义。
11         self.name = name
12 
13     def getName(self): # 实例方法定义。
14         return self.name
15 
16     def setName(self, value):
17         self.name = value
18 
19 print(Animal.name) # 未知
20 print(Animal.__dict__["name"]) # 未知
21 
22 animal = Animal("狗狗")
23 print(animal.name) # 狗狗
24 print(animal.__dict__["name"]) # 狗狗
25 print(Animal.name) # 未知
26 print(Animal.__dict__["name"]) # 未知
27 print(animal.__class__.name) # 未知
28 print(animal.__class__.__dict__["name"]) # 未知
复制代码
复制代码
1 # 类型定义中的代码会执行,是一个独立的作用域。
2 class TestClass:
3     print("类型定义中") #类型定义中
复制代码

绑定方法和未绑定方法

复制代码
 1 class TestClass:
 2     def method(self):
 3         print("测试方法")
 4 
 5 test = TestClass()
 6 print(TestClass.method) #<unbound method TestClass.method>
 7 print(test.method) #<bound method TestClass.method of <__main__.TestClass object at 0x021B46D0>>
 8 
 9 TestClass.method(test) #测试方法
10 test.method() #测试方法
复制代码

绑定方法已经绑定了对象示例,调用的时刻不用也不能传入self参数了。

注:使用对象访问实例方法为何会返回绑定方法?这个还得等到学完“魔法方法”才能解释,内部其实是拦截对方法成员的访问,返回了一个Callable对象。

私有成员

复制代码
1 # 私有成员
2 class TestClass:
3     __private_property = 1
4 
5     def __private_method():
6         pass
7 
8 print(TestClass.__dict__) # {'__module__': '__main__', '_TestClass__private_method': <function __private_method at 0x0212B970>, '_TestClass__private_property': 1
复制代码

难怪访问不了了,名称已经被修改了,增加了访问的难度而已。

多重继承

复制代码
 1 #多重继承
 2 class Base1:
 3     pass
 4 
 5 class Base2:
 6     pass
 7 
 8 class Child(Base2, Base1):
 9     pass
10 
11 child = Child()
12 print(isinstance(child, Child)) # True
13 print(isinstance(child, Base2)) # True
14 print(isinstance(child, Base1)) # True
复制代码

如果继承的多个类型之间有重名的成员,左侧的基类优先级要高,上例子Base2会胜出。

接口那里去了,鸭子类型比接口更好用。

复制代码
 1 class TestClass1:
 2     def say(self):
 3         print("我是鸭子1")
 4 
 5 class TestClass2:
 6     def say(self):
 7         print("我是鸭子2")
 8 
 9 def duck_say(duck):
10     duck.say()
11 
12 duck_say(TestClass1()) # 我是鸭子1
13 duck_say(TestClass2()) # 我是鸭子2
复制代码

调用父类

复制代码
 1 # 调用父类
 2 class Base:
 3     def say(self):
 4         print("Base")
 5 
 6 class Child(Base):
 7     def say(self):
 8         Base.say(self)
 9         super(Child, self).say()
10         print("Child")
11 
12 child = Child()
13 child.say()
复制代码

魔法方法

详细内容参考:http://www.rafekettler.com/magicmethods.html

对象构造相关:__new__、__init__、__del__。

复制代码
 1 from os.path import join
 2 
 3 class FileObject:
 4     '''Wrapper for file objects to make sure the file gets closed on deletion.'''
 5 
 6     def __init__(self, filepath='~', filename='sample.txt'):
 7         # open a file filename in filepath in read and write mode
 8         self.file = open(join(filepath, filename), 'r+')
 9 
10     def __del__(self):
11         self.file.close()
12         del self.file
复制代码

运算符重载:所有运算符都能重载。

复制代码
 1 class Word(str):
 2     '''Class for words, defining comparison based on word length.'''
 3 
 4     def __new__(cls, word):
 5         # Note that we have to use __new__. This is because str is an immutable
 6         # type, so we have to initialize it early (at creation)
 7         if ' ' in word:
 8             print "Value contains spaces. Truncating to first space."
 9             word = word[:word.index(' ')] # Word is now all chars before first space
10         return str.__new__(cls, word)
11 
12     def __gt__(self, other):
13         return len(self) > len(other)
14 
15     def __lt__(self, other):
16         return len(self) < len(other)
17 
18     def __ge__(self, other):
19         return len(self) >= len(other)
20 
21     def __le__(self, other):
22         return len(self) <= len(other)
23 
24 print(Word("duan") > Word("wei"))
复制代码

属性访问。

复制代码
 1 class AccessCounter:
 2     '''A class that contains a value and implements an access counter.
 3     The counter increments each time the value is changed.'''
 4 
 5     def __init__(self, value):
 6         super(AccessCounter, self).__setattr__('counter', 0)
 7         super(AccessCounter, self).__setattr__('value', value)
 8 
 9     def __setattr__(self, name, value):
10         if name == 'value':
11             super(AccessCounter, self).__setattr__('counter', self.counter + 1)
12         # Make this unconditional.
13         # If you want to prevent other attributes to be set, raise AttributeError(name)
14         super(AccessCounter, self).__setattr__(name, value)
15 
16     def __delattr__(self, name):
17         if name == 'value':
18             super(AccessCounter, self).__setattr__('counter', self.counter + 1)
19         super(AccessCounter, self).__delattr__(name)
复制代码

集合实现。

复制代码
 1 class FunctionalList:
 2     '''A class wrapping a list with some extra functional magic, like head,
 3     tail, init, last, drop, and take.'''
 4 
 5     def __init__(self, values=None):
 6         if values is None:
 7             self.values = []
 8         else:
 9             self.values = values
10 
11     def __len__(self):
12         return len(self.values)
13 
14     def __getitem__(self, key):
15         # if key is of invalid type or value, the list values will raise the error
16         return self.values[key]
17 
18     def __setitem__(self, key, value):
19         self.values[key] = value
20 
21     def __delitem__(self, key):
22         del self.values[key]
23 
24     def __iter__(self):
25         return iter(self.values)
26 
27     def __reversed__(self):
28         return FunctionalList(reversed(self.values))
29 
30     def append(self, value):
31         self.values.append(value)
32     def head(self):
33         # get the first element
34         return self.values[0]
35     def tail(self):
36         # get all elements after the first
37         return self.values[1:]
38     def init(self):
39         # get elements up to the last
40         return self.values[:-1]
41     def last(self):
42         # get last element
43         return self.values[-1]
44     def drop(self, n):
45         # get all elements except first n
46         return self.values[n:]
47     def take(self, n):
48         # get first n elements
49         return self.values[:n]
复制代码

可调用对象,像方法一样调用对象。

复制代码
 1 class Entity:
 2     '''Class to represent an entity. Callable to update the entity's position.'''
 3 
 4     def __init__(self, size, x, y):
 5         self.x, self.y = x, y
 6         self.size = size
 7 
 8     def __call__(self, x, y):
 9         '''Change the position of the entity.'''
10         self.x, self.y = x, y
11         print(x, y)
12 
13 entity = Entity(5, 1, 1)
14 entity(2, 2)
复制代码

资源管理

复制代码
 1 class Closer:
 2     def __enter__(self):
 3         return self
 4 
 5     def __exit__(self, exception_type, exception_val, trace):
 6         print("清理完成")
 7         return True;
 8 
 9 with Closer() as closer:
10     pass
复制代码

对象描述符。

复制代码
 1 class Meter(object):
 2     '''Descriptor for a meter.'''
 3 
 4     def __init__(self, value=0.0):
 5         self.value = float(value)
 6     def __get__(self, instance, owner):
 7         return self.value
 8     def __set__(self, instance, value):
 9         self.value = float(value)
10 
11 class Foot(object):
12     '''Descriptor for a foot.'''
13 
14     def __get__(self, instance, owner):
15         return instance.meter * 3.2808
16     def __set__(self, instance, value):
17         instance.meter = float(value) / 3.2808
18 
19 class Distance(object):
20     '''Class to represent distance holding two descriptors for feet and
21     meters.'''
22     meter = Meter()
23     foot = Foot()
复制代码

Mixin(也叫掺入)

掺入模块:playable.py

复制代码
1 # coding=utf-8
2 
3 def paly(self):
4     print("游戏中...")
复制代码

掺入目标模块:test.py

复制代码
1 # coding=utf-8
2 
3 class Animal:
4     from playable import paly
5 
6 animal = Animal()
7 animal.paly() # 游戏中...
复制代码

Open Class(打开类型,从新定义成员)

复制代码
 1 #coding:utf-8
 2 
 3 class TestClass:
 4     def method1(self):
 5         print("方法1")
 6 
 7 def method2(self):
 8     print("方法2")
 9 
10 TestClass.method2 = method2
11 
12 test = TestClass()
13 test.method1() # 方法1
14 test.method2() # 方法2
复制代码

Meta Programming(元编程)

复制代码
1 TestClass = type("TestClass", (object,), {
2     "say": lambda self : print("你好啊")
3 })
4 
5 test = TestClass()
6 test.say()
复制代码
复制代码
 1 def getter(name):
 2     def getterMethod(self):
 3         return self.__getattribute__(name)
 4     return getterMethod
 5 
 6 def setter(name):
 7     def setterMethod(self, value):
 8         self.__setattr__(name, value)
 9     return setterMethod    
10 
11 class TestClass:
12     getName = getter("name")
13     setName = setter("name")
14 
15 test = TestClass()
16 test.setName("段光伟")
17 print(test.getName())
复制代码

AOP(面向切面编程)

整理中

备注

Python在作用域方面非常接近JavaScript,类型和对象系统也有几份相似(虽然Javascript是基于原型的),Javascript、PHP、Python和Ruby这几门语言交叉学习会带来意想不到的收获。

 

[转载]ASP.NET利用Memcached的分布式Session来提升性能 - IT青藤屋 - 青藤园

mikel阅读(1205)

[转载]ASP.NET利用Memcached的分布式Session来提升性能 – IT青藤屋 – 青藤园.

摘要:很多时候,我们在使用ASP.NET的Session都是 将Session保存到网站进程中去,或者将Session保存到SQLServer或stateserver中,当然,一般情况下,这种方法肯定能满足 要求了。但是,单服务器存储Session始终会随着应用规模的扩大而出现瓶颈,这时候我们就需要搭建分布式Session了,下面这篇文章就是通过 Memcached的分布式特性来实现ASP.NET的Session分布式存储,原文如下:

如果我们正在使用Session,那么构建高性能可扩展的ASP.NET网站,就必须解决分布式Session的架构,因为单服务器的 SESSION处理能力会很快出现性能瓶颈,这类问题也被称之为Session同步。微软有自己的分布式Session的解决方案,那就是 SessionStateServer,我们可以参考:

ASP.NET Session State Partitioning

http://blog.maartenballiauw.be/post/2008/01/23/ASPNET-Session-State-Partitioning.aspx

ASP.NET load balancing and ASP.NET state server

http://blog.maartenballiauw.be/post/2007/11/ASPNET-load-balancing-and-ASPNET-state-server-(aspnet_state).aspx

不过本文是要换一个方案,那就是使用Memcached来到达分布式SESSION的架构。Memcached作为分布式的缓存服务器已经被广泛应用在网站建设中。

一:Session的机制

Session是针对用户的,我们也可以理解为是针对浏览器的。在浏览器首次访问ASP.NET网页的时候(网页没有关闭session功能),它会发送如下的HTTP头给客户端:

浏览器在收到上面的HTTP头后,会将这个唯一的SESSIONID保存在自己的COOKIE中(只要没有禁用COOKIE,本文不讨论禁用 COOKIE的案例,可参考本博文http://www.cnblogs.com/fish-li/archive/2011/07/31 /2123191.html,写的很NICE)。当浏览器再次请求服务器进行访问的时候,它会在请求HTTP头中加入如下的标识,我们可以看到,这个 SESSIONID就是上面的SESSIONID:

浏览器和服务器间就是通过这样一种机制来确保用户SESSION的。

如果客户端浏览器禁用了Cookie会怎么样,我们会发现每一次刷新浏览器Set-Cookie都是不同的,而发送请求头中也永远不会出现 Cookie标识。这个时候,我们会发现Session失效了(当然,微软为了防止出现这种情况,允许我们在sessionState中设置 cookieless=”true”,用URL来传递sessionid)。

二:Memcached Providers

我使用的Memcached客户端是Memcached Providers,下载完毕后,你会发现Memcached Providers已经提供了对分布式Session的支持功能。如果你还不会使用Memcached Providers,请参考此文Memcached Tip 1:使用Memcached Providers。Memcached Providers提供的示例是直接将SESSION存储在数据库,我们可以通过配置来将SESSION支持存储在分布式SESSION的内存中,即,将 下文中的dbType由SQL修改为none。:

使用Memcached Providers提供的分布式Session没有任何特别之处,因为Memcached Providers提供的SessionStateProvider类型实现的是ASP.NET中的 SessionStateStoreProviderBase这个抽象类,我们可以看到配置文件中指定了Session的处理类是 SessionStateProvider,所以,ASP.NET在接受到客户端的请求后,会自觉滴使用SessionStateProvider来处理 所有的SESSION,也正是这个类,完成了将SESSION读取和存储在Memcached中(如果设置了SQL,则会同步存储到SQLServer数 据库)。

SESSION的设置和读取与传统没有任何区别,读:

1
2
Session["sname2"] = "sluminjxxi"
Session.Timeout = 2;

取:

1
Response.Write(Session["sname2"]);

三:为什么要配置SQL

传统的SESSION的缺点,在仅使用dbType为none配置的时候都会存在。如Memcached的内存到达上限的时候会怎么 办?Memcached使用LRU淘汰算法(最久未使用),在这里我们不需要去细究这个算法在Memcached内部到底是什么样一个机制,我们只需要知 道,在内存紧张的时候,即使SESSION时间未到,Memcached也有可能把它干掉。所以,保险的做法是,在Memcached之下,再加上 SQLServer的持久化保存。如果缓存命中的,直接取缓存,如果缓存没命中的,则再到数据库中确认一次。当然,这样会带来一些性能损耗,但是却是更安 全的做法。

Memcached Providers提供的下载文件中,提供了初始化SESSION的一些脚本,正确执行后,它会生成如下一个表tblSessions,及若干存储过程:

tblSessions保存的是就是单独的Session,如下:

四:Memcached Providers的一个BUG

在当前的Memcached Providers(1.2版本)中关于SessionStateProvider(29520-TRUNK)是有一个BUG(我已提交到 codeplex,相信他们的下一个版本应该能得到修正)的。如果我们测试SESSION失效时间,发现只要经过一次刷新后,就永远是20分钟(即默 认)。这源于在ReleaseItemExclusive这个重载方法中(该方法用于释放对会话数据存储区中项的锁定),对于Session的重新存储没 有加上过期时间,如下:

注释掉的是Memcached Providers提供的源码,而正确的应该是我修正过的上一条。使用修正过的DLL,一切圆满了。

五:采用数据库存储SESSION的可扩展问题

随着访问量的进一步上升(当然,到了这种程度,说明网站做的很很成功,绝大部分的网站是不需要考虑这一步的),即便我们使用了Memcached作 缓存,使用单一的SQLSERVER存储SESSION仍旧带来了性能问题,在这种情况下,我们对于数据库的设计可以采用水平分区的架构,即根据某种算法 (可以根据SESSIONID,或者用户名等)将SESSION存储到不同的数据库中。这个时候,如果我们仍旧使用Memcached Providers,那么必须进一步修改源码了,由原先支持单一SQLSERVER服务器,编程支持多个服务器。当然,如果不喜欢SQLSERVER,还 可以修改为支持mysql、mongodb、任何自定义的KEY-VALUE框架等等,此为后话,暂且不表。

原文链接:http://www.cnblogs.com/luminji/archive/2011/11/03/2195704.html