起因

因为业务需要,计划实现一个WSGI application,用于现有逻辑. 实现WSGI时碰到需要进行URL匹配的问题了.有人提议能否能像SQL中的查询一样,进行预处理缩小被匹配的正则范围.

这里有几个值得考虑的地方. - 如何进行缩小匹配正则范围. - 额外的一次字符串匹配(startswith)的消耗是否小于缩小后的正则匹配消耗.

验证

首先进行正则表达式的处理,获取正则中能用于字符串匹配的"开头几个"字符. 这就涉及到正则表达式的解析了.好在Python的成熟类库,自带提供了解析正则表达式的库

正则表达式解析

re.sre_parse提供了对正则表达式的解析. 返回的是每个字符的类型.有"literal"的常规字符.也有"in"的正则捕获,还有"max_repeat"的贪婪匹配等等.

In [28]: a.parse("/asdas\wd\sa\Wsssss\Safadf\Dsd\d+a[^a]*dasdasd")
Out[28]: [('literal'47), ('literal'97), ('literal'115), ('literal'100), ('literal'97), ('literal'115), ('in', [('category''category_word')]), ('literal'100), ('in', [('category''category_space')]), ('literal'97), ('in', [('category''category_not_word')]), ('literal'115), ('literal'115), ('literal'115), ('literal'115), ('literal'115), ('in', [('category''category_not_space')]), ('literal'97), ('literal'102), ('literal'97), ('literal'100), ('literal'102), ('in', [('category''category_not_digit')]), ('literal'115), ('literal'100), ('max_repeat', (165535, [('in', [('category''category_digit')])])), ('literal'97), ('max_repeat', (0, 65535, [('not_literal'97)])), ('literal'100), ('literal'97), ('literal'115), ('literal'100), ('literal'97), ('literal'115), ('literal'100)] 

 

有了re.sre_parse之后处理就变得简单了.碰到非字符常量就截取到当前位置字符,作为匹配键.

其他逻辑实现

其他的逻辑就很直接了,直接模拟WSGI application的URL匹配操作.与regex_match各用29s,21s.

import re


match_list 
= [
    (
"/sss""dataA"),
    (
"/ddd\d+""dataB"),
    (
"/asd\W+""dataC"),
    (
"/bbb""dataD"),
]

match_list_start 
= []
for n, i in enumerate(match_list):
    reg_nodes 
= [0 if node[0] == "literal" else 1 for node in re.sre_parse.parse(i[0])]
    position 
= -1
    
try:
        position 
= reg_nodes.index(1)
    
except ValueError, ex:
        
pass

    match_list_start.append(i[0][:position] 
if position > -1 else i[0])

    match_list[n] 
= (re.compile(i[0]), i[1])

def str_match(ls):
    
for i in ls:
        
for n, j in enumerate(match_list_start):
            
if i.startswith(j):
                match 
= match_list[n][0].match(i)
                
if match:
                    
#domatchting
                    pass

def regex_match(ls):
    
for i in ls:
        
for j in match_list:
            match 
= j[0].match(i)
            
if match:
                
#domatching
                pass


example_str 
= [
    
"/ssssssssssss",
    
"/ddd123123",
    
"/asd4134134asdasd",
    
"/bbbbbbbbbbbbbbb",
    
"/bbb",
    
"/sss",
    
"/dddwww",
    
"/asdWWWWWW",
* 800000

str_match(example_str)
regex_match(example_str) 

 

结果大家可以自己测一下.我这编跑是耗时95s,str_match

结论

在cProfile反馈的数据中光是string的startswith耗时16s.后来只执行regex.match耗时21s. 所以直接进行正则匹配更为有效.

 本文原文: http://huangxin.im/2011/4/WSGI_is_the_match_before_the_URL_should_narrow_the_scope_of_the_regular_match.html 

posted @ 2011-04-22 16:27 Dreampuf 阅读(942) 评论(1) 编辑
  今天看到某位童鞋的笔记,提出了一个HTML + CSS + JS就是一个MVC 的观点,大意就是由HTML提供数据模型,CSS负责视图显示,JS来总管逻辑控制,列举了将一部分HTML写在JS中到用时还是需要copy CSS十分不便捷,还附带一句"前端不像后台那样能够一门语言吃天下",笔者不敢苟同,拿出一些看法供君判断一二.

 

第一:
    后端没有一语言定天下.相比前端的多浏览器.后端还是非常多的领域语言必须掌握,多个平台的区别(不是浏览器),语言上T-SQL访问数据库,shell管理服务器,而多个业务平台交互更是交融反复(笔者常使用的Python调用C模块只是一个小例子,为什么XML曾经被寄以众望. Web Service不正是为了解决这种跨平台的工具么)
第二:
    HTML绝不仅仅只是Model.还有多的视图成分在里面.HTML在很长的一段时间里都被人诟病,因为包含的内容太多,CSS,JS,图片甚至Flash,Java app…不能不说混杂.即便如今html5也改变不了他的视图身份,这里要注意:浏览器是解析HTML来生成页面的,而不是CSS,HTML由于包含太多,所以不能仅仅作为模型存在.
    前端也不一定非要往MVC里硬套.而且MVC本身存在很多问题,诸如结构不灵活,衔接不紧密等等.所以又会有MVP,MVVP等多个拓展模式.需要注意的一点,MVC提供给我们最基础的是一种分层思想,而不是固定不变的视图模型和控制器.
    比HTML+CSS+JS更MVC的应该是XML+XSL+XPATH,这套组合才是完全的MVC.CSDN就是使用的这套.
第三:
    将部分功能独立出来时,犹豫HTML本身包含太多,所以还是会碰到又要copy CSS, JS之类的.

     我曾经也碰到过,那时我的解决方法是全部动态加载,使用JS.益处是完全作为了一个独立的模块,引入js就可以了,弊处就是所有修改都在JS总以字符串的形式修改,没有IDE的辅助略显麻烦,但是他们(HTML,CSS,JS)谁又不是能任意编辑的字符呢?

posted @ 2011-03-01 18:39 Dreampuf 阅读(2522) 评论(20) 编辑


作者: dreampuf
日期: 2011-02-18 23:22:50

1   简介

记录了个人在需要时阅读django源码时的一些阅读笔记.所有笔记基于 django v1.0.4.

2   Cache

2.1   BaseCache

django中缓存是一个独立的组件,它定义了一个父类,文件在 django/core/cache/backend/base.py 这个模块包含了一个父类 BaseCache ,指定了一些基础的操作.
  • __init__ :初始化指定了缓存项的过期时间,但是根据具体实现的不同会有不同的解释. (比如在数据库实现中就是删除数据项)
  • add :添加缓存,参数分别为 过期时间 (默认是300秒).这个方法由子类实现.
  • get :获取缓存,参数为  , 默认值 (默认为None).
  • set :改变缓存,参数同 add 函数.
  • delete :删除缓存,参数为 .
  • get_many :获取多个缓存, 参数为 键列表.
  • has_key :是否存在键, 参数为 .
  • __contains__ :判断是否存在的函数, 参数为 .结果与 has_key 一致.

2.2   DataBaseCache

基于数据库的缓存.模块文件在 django/core/cache/backend/db.py 这个文件包含了一个继承BaseCache的数据库缓存实现. 他还指定了数据库最多存多少缓存项.

其中值得注意的几点是:

  • 使用pickle序列化对象.所以存储任何对象都是可以的,最后都会被转化为数据库支持的字符串.
  • 过期时间是以秒为单位.
  • 每次 set 都会处理序列化,哪怕本身存储的就是字符串.这显然不太合算.
  • 构造缓存管理对象的时候可以指定一个 cull_frequency 参数,作为超过最大项时删除的参考,默认是 3,也就是说每当超过容量限制时,删除1/3的缓存数据项.奇怪的是,这里是根据 cache_key 的大小删除,而不是根据过期时间,这样就可能导致 时效非常久的缓存被提早就给删除 了.
  • 每次获取时进行过期处理,也就是说可能有一些项永远都会存在数据库中.(过期后,自身cache_key非常大,极少有被删除的可能)

2.3   DummyCache

测试使用的缓存.模块文件在 django/core/cache/backend/dummy.py.这个缓存功能相当有限,仅仅只能被用于测试.而且本身无任何逻辑,只是返回一些默认值.

2.4   FileBaseCache

基于文件的缓存.模块文件在 django/core/cache/backend/filebase.py.这个文件系统缓存,实现了基于每个缓存对象一个文件的对应.只是在处理多文件管理时,使用了一些必要的方法.
  • 构造时传递的第一个为路径地址.
  • add 方法如果添加已存在的键时不会成功,这和我们寻常的逻辑有点不符,如果还需要调用 add 那么肯定是想指定值,所以如果添加一些已有键,势必会添加一次判断.
  • 每次 set 是都会进行一次目录遍历,搜索所有文件,看是否超过总数.
  • 文件名的生成是对 cache_key 进行一次md5,然后取加密后的字符两个前两位作为一个二级目录存放(比如: ab/cd/*****),这样是为了目录下的文件过多时索引文件非常慢而导致效率很低的问题.但是结合构造函数时接受的最大缓存项来看,默认的 300 根本无法构成对文件索引拖慢的威胁.而 FileBaseCache默认就使用二级目录预估的至少可以存储 1000*1000 项缓存数据(假设缓存文件平均分布).是否是因该有所优化的在构造时加上一个判断,只有在一定数量级之后才启用二级目录,或者增加一个一级目录管理,再或者默认不设目录.

2.5   LocamemCache

基于内存的缓存,模块文件在 django/core/cache/backend/locamem.py.实现了简单的内存缓存系统.

实现了带锁的内存缓存系统,不过有些瑕疵,好像是为了保证整体统一,不过这种统一难免让人诟病.

  • 构造时内部声明了两个字典,一个存放序列化之后的缓存值,一个存放设置好了的过期时间,并且额外声明了一个异步锁.不过据我所知 Python 的多线程简直就是在自慰, GIL 使然,你根本无法放开手脚,虽然值得解释器环境更加安全稳定,但是这种 伪多线程 很难让人提起兴趣.
  • 在添加缓存时,获取缓存时,依然不辞幸苦给缓存值进行了序列化.作为的 dict 可能唯一的感受就是嫉妒羡慕恨.
  • 在超出缓存最大值之后, LocamemCache 将会删除所有与 _cull_frequency 取模为0的值.仅仅是为了使用 生成器表达式?!如果 _cull_frequency 为0时,则清空缓存库.但是当 _cull_frequency 为1时,同样会有清空缓存库的效果.

2.6   MemcachedCache

基于memcached的缓存系统,模块文件在 django/core/cache/backend/memcached.py.简单的对cmemcache或者memcache的封装.

这下django终于机灵了,没有在这里序列化了,因为这些动作会在memcache库中操作.

  • 所有传入的 unicode字符 被转换为 utf-8,从缓存中获取的字符串则被转换为 unicode字符.
  • 如果在 set 或者 add 方法中指定过期时间为 0 不过期有可能是无效的,因为 MemcachedCache 在处理默认过期时间时采用了一个 逻辑或 处理,所以导致如果指定为 0 被逻辑操作为 传递默认值.
  • 他有一个额外的关闭连接方法(close),默认是不会自己调用的,需要在每次使用之后手动调用.
posted @ 2011-02-20 15:13 Dreampuf 阅读(1575) 评论(1) 编辑

    最近在看Python,可惜前有古人,后面也想必会有一堆来者,难免不和以前喜爱的JavaScript,C#比较一番.于是遂有此篇.各位看官,您只管一眼扫去,切莫往心里去,我不能误这个子弟.

 "Lambda"

    这里说的Lambda统指一切能够作为"参数传递的'函数'".这里函数还打了一对单引号,因为C#对应的是Delegate原因

    JavaScript: 无法让人释怀的First Class type. 弱类型, First Class对象,正如引用里的链接回答的:"能够从函数中返回,能够传递给函数,能够在运行时构造".而JavaScript相较Python的就是拥有多行执行,相对来说容量比较"大", 缺点也不是没有, 引用对象的绑定依据环境而变化,不过这也是脚本环境的通病哈,这时就需要构造一个闭包环境来帮助我们帮定相应的引用对象. 当然还有一个是关键字冗余,写多了难免觉得有些多余.

var divs = $("div");
for(var i = divs.length; i > 0; i--) {
    divs[i].click(
function(){
        alert(divs[i]); 
//also alert(this)
    }
}

 

 

    Python: 相对来说只能执行一行代码,自动返回,不需要return关键字.

    C#: C# 1.0给出的方案是delegate ,让delegate作为函数的包装,在方法中传递. 随后C# 2.0的匿名函数就已经很相似了, C# 3.0给出了满意的答案,一个"=>"进一步简化了delegate关键字冗余,而且随之而来的匿名类型,Linq将生产力推向一个高峰.

 

Functional Programming

    注意,这里所指"函数编程"不是在讨如如何在这三门语言里进行"函数化"代码的编写,而是记录一些三门语言对于函数式编程提供的一些类库,辅助函数等软环境.老赵的引文编程语言的发展趋势及未来方向(3):函数式编程  大家可以前去看看. 函数式编程相对于命令式编程,命令式处理只要包含几个分支判断,循环处理,重在如何解决问题. 而函数式则不同,重在解决什么问题.

    JavaScript: 提供了强大的元编程能力, 无论是first class的function,还是函数对象的toString方法,都为函数式编程提供了基础,而函数式编程则又带来了诸多优点.二者日相彰益.不过一些基础设施明显不足,没有提供一个良好的可枚举对象方案,对集合对象的操作倍感乏力.

Array.prototype.map = function(func) {
    
for(var i = this.length; i > 0; i--) {
        func(
this[i]);
    }
}

 

    Python: 完美的函数式编程,无论是map, zip 等等各种内置函数,还是各类可枚举类型, 元编程等等都是更胜一酬. 不过代码方面强制缩进作为程序是否正确的标准, 代码好看了,程序却显得有些古板, 不个性(恩恩,个性)

 import sys,  operator

= range(5)
map(
lambda x: sys.stdout.write(x), a)
reduce(operator.add, a)

 

    C#: 不提1.0,2.0. C# 3.0 有点老树新开, 加入F# 后,C#的函数化跟着也上升好几个档次, 相较于前两者的弱类型脚本语言,强类型的C#肯向脚本化靠拢,而且提供了一个不错的脚本化环境. LINQ 为C# 对集合的操作提供了强大的增益(相对于1.0, 2.0).

 

 模式

    我们都知道设计模式为我们要解决的问题提供了成熟的解决方案,模式已经或多或少的成为了我们开发的必需品.

    JavaScript: JavaScript的原型链不就是职责链的完美实现么.

 代码

var A = function(){ 
            
this.helloA = function() {
                              alert(
"Hello A");
              };
         },
    B 
= function(){
          
this.onlyB = function(x) { 
                      alert(x);
          }
     };
B.prototype 
= new A();
= new B();
a.helloA();

 

 

    Python: yield 实现了枚举器,各个可枚举对象同样都是如此,装饰器, 模块实现了单例, 继承方式又有点像原型链(__metaclass__属性).设计模式可谓在Python中发挥的淋漓尽致.

    C#:  Event 实现了监听者模式, IEnumerable 枚举对象...

    在语言的层次上是否需要这么多的"模式"作为标准还没有定论,不过可以明确的是越来越多内置的"模式"为我们的开发极大的带来了便捷,这也是各位能够感同身受的.

 

    好了,各位看官,我将三门语言从三个语言的角度谈了一点自己的想法,这三个角度不全面,相反,还有些片面,不过,这里是我个人给出的一个答案,而且还不是标准的.您肯定还有一些不吐不快的,能不能拿出来一块分享呢?

    注:这里只是比较语言的区别,并没有优劣,他们各有千秋,python和C#不会跑到客户端去代替JS,C#和python互相也没什么好代替的.所以,在这里声明一下.

posted @ 2011-01-14 12:12 Dreampuf 阅读(1934) 评论(2) 编辑

     除了枯燥的看看题解,做做题外,偶尔还做做实例,放松放松心情.前段时间也摆弄过Google Engine App(下简称GEA),以前依次在上面部署过Python,Java的应用,不过还真没怎么做真正的开发,一来环境不熟悉,二来功底不够.忽闻AppengineJS发布马上部署了一个,欣喜若狂的打算做个JavaScript(下简称JS)应用,不过静下心来,发现很多问题.

 

为什么不做JavaScript服务端开发

 

  • 没有合适的JavaScript Runtime(JSR ?)
        现在JS之所以能够流行,很大程度上取决于浏览器的普及.浏览网页的时候需要计算一道简单的四则混合运算,你会怎么做?心算?打开计算器然后点几个按钮?我的方法是在浏览器地址栏输入"javascrit:alert(1+2+4*5);".很方便不是么.
        但是服务端的情况就不容乐观,除了少数几个解析器能够勉强运行单薄的JS语法,似乎很难让他在服务端大展拳脚.V8?嗯,确实很快,不过还只是个跑在客户端的小伙子.Node.js?嗯,的确提出了很多特性,不过就拿这些特性想征服服务端的开发还是不容乐观.RingoJS?JVM的庞大,让JS无法灵巧的伸展.IronJS?无案例,无图,无真相.
  • 没有成熟的类库
        你愿意在一片荒芜的土地上开荒,还是在肥沃的农田挥锄?
        JS在客户端确实意气风发,jQuery,Prototype,YUI,Ext,Dojo等等.无数的框架,为我们的网页动态化提出了解决方案之道.在这百家争鸣的日子里,众多特性,理念,被提出来,链式操作,函数式编程....一片繁华.
        反观JS在服务端的表现,集合操作停留在增删改,没有filter,没有order.字符串只能拼接,没有格式化.文件读写就一个CommonJS标准.数据交互的确得益于JSON的流行,很方便,但是数据存储似乎又回到了ASP/VBScript时代.
  • 标准
        就像客户端浏览器对JS的支持参差不齐,服务端对于CommonJS标准也是有待加强.所幸服务端JS没有跨"浏览器"之忧.
  • 效率
        开发效率顶呱呱的JS在服务端由于缺少类库的支持,使得服务端开发相比现存的几个平台(JVM,.NetFX),慢了不止几个档次.客户端就备受诟病的执行效率放到服务端仍旧是一个不可忽视的问题.

为什么要看好JavaScript服务端开发

 

  • 灵巧
        没人否认JS本身强大的灵活性,强大的自解析,原型链和弱类型衍生出的种样繁多的开发方式.实在是让人爱不释手.
  • 普及
        JSON确实有XML不可比拟的潜质,体积瘦小,方便传输.众多语言中都有支持.客户端无需插件就能原生解析.还有什么比这更棒的么?
  • 活跃的社区
        一个篱笆三个桩,一个好汉三个帮.活跃的JS社区不会甘心JS止步与客户端,必然会向服务端虎视眈眈.

    AppengineJS使用一段时间后有感而发.

原文地址: http://www.macgoo.com/myblog/archives/166/

posted @ 2010-10-18 11:33 Dreampuf 阅读(2988) 评论(7) 编辑
摘要: 大多数人都是如何使用网络?您在邮件,QQ,Twitter,Facebook等等程序里在新的标签里打开他们带来的连接. 然后,等到某个闲暇的时间,阅读这些打开的标签,对不对?更甚,某些文章有8页长,让您不得不提前打开几个页面来加载他.然后也许在您的浏览器崩溃或者系统重启的时候才想起来,你为什么要打开他. 这是不理智的,我拒绝使用这种方式浏览网站,下面是我的做法. 考虑下面的新的流程,看过之后,您将会...阅读全文
posted @ 2010-08-29 03:33 Dreampuf 阅读(10960) 评论(8) 编辑
摘要: 这本该是半年以前该做的事了. 这个项目前前后后折腾了近半年.在项目开始的时候,我在弄一个比赛,在那比赛的时候挺2的,没能夺魁.回来后项目也进行了近一个月.可丝毫没有进展的样子.还只是模模糊糊的画出了数据库设计. 项目分为三组,开始定好每组五人,结果因为童鞋们兴趣挺浓,就每组多了一人.整整十八个人,花了半年时间,就折腾出这么个东西,也只想到欲哭无泪这个词儿来形容了. 项目一开始我也是满心欢喜的...阅读全文
posted @ 2010-08-10 23:25 Dreampuf 阅读(259) 评论(0) 编辑
摘要: 最近在封装EntityFramework的时候碰到许多问题,下面就做一个简短的笔记.泛型推断例如Save<T>(T o)这样的方法是没有问题的,但是如果参数再包裹一层泛型就不行了,Save<T>(IEnumerable<T> o),所以只能在方法体类判断是否实现了IEnumerable<T>接口,然后分情况处理.关于更多C#3.0中的泛型推断.大体上...阅读全文
posted @ 2010-07-23 13:07 Dreampuf 阅读(257) 评论(0) 编辑
摘要: 通过本篇,你能了解到 Asp.net MVC 模型绑定处理过程,一种解决并发颗粒度到一条数据的方法. * 如何解决互联网中某条数据的并发问题 在一个页面提交数据库前把从数据库取出的数据和提交时数据库中的数据比较,不同则给出提示. 在和其他童鞋的讨论中,都明确的指出了采用HashCode的方案,HashCode作为区分对象不同的一种方案,确实可行,但也有反对的声音.采用HashCode难免会涉及到...阅读全文
posted @ 2010-07-15 23:41 Dreampuf 阅读(2426) 评论(4) 编辑
摘要: 满是坎坷的完成了这个DAO,间或断了几次,对MSDN欲求不满,还好Google在. 在VS中生成了映射文件,以及实体类后,简单配置一下就可以使用了,请各位指点迷津,这样写法是否妥当,千万别把这个类拿去搞生产,否则后果自负,作者不承担任何后果. 我们知道,一般的项目都是分了几层,而其中少不了对于数据持久化的管理,也就是数据访问层,在被Hibernate的配置淹没后,被DbEntry.net(国产...阅读全文
posted @ 2010-07-08 23:03 Dreampuf 阅读(1932) 评论(4) 编辑