跬步 On Coding

Python协程

https://zh.wikipedia.org/zh-cn/%E5%8D%8F%E7%A8%8B

协程可以理解为线程中的微线程,通过手动挂起函数的执行状态,在合适的时机再次激活继续运行,而不需要上下文切换。所以在python中使用协程会比线程性能更好。

Tornado协程

http://blog.csdn.net/wyx819/article/details/45420017

上面有大牛分析的Tornado的线程实现,依赖与Tornado的IOLoop,所以不能单独拿出来使用。有几个需要理解的概念:

  1. Future对象 用来保存异步获取到的结果,并在set_reslut的时候调用callback方法,把对应的callback方法放到ioloop的callback列表中等待下一次ioloop循环再执行
  2. 装饰器coroutine 在这个装饰器中实现了协程的调度,通过不断的调用next函数来不断获取Future对象,然后每次拿到Future对象在add_callback到ioloop上,等到Future被set_reslut后再次next,直到生成器中抛出Return的异常。

具体的实现过程不是很好描述,调度过程比较复杂,还是看看参考文章大牛的解析吧。

Tornado代码阅读笔记 IOLoop

准备用Tornado + greenlet + Django ORM搭一个框架,大体上有个思路,在开始前再次阅读下Tornado的代码。目的是在学习Torndao使用的同时,了解下原理,以便在使用过程中少踩点坑。

准备

  1. 学习IO多路复用: epoll
    http://scotdoyle.com/python-epoll-howto.html
    https://fukun.org/archives/10051470.html

  2. Reactor模型
    http://blog.csdn.net/u013074465/article/details/46276967

去年大概这个时候也硬着头皮读过Tornado的代码,当时没有经验,还不知道编程模型,在程序的理解上都是顺序执行的思路,所以看到Tornado的代码只会觉得特么的牛B,各种类,各种方法的调来调去。现在理解了Reactor模型以后,再回过头看Tornado,就比较容易理解了,所以在阅读代码前如果能在构架上先理解,读起来会快很多。

Tornado的代码基于2.0版本,最新的4.3版本读起来比较绕,抽象的更加细化,阅读代码的目的在于学习编程思路,不求新。

haystack-Elasticsearch实现拼音搜索

前一篇Django+Elasticsearch实现搜索功能已经实现了搜索的基本功能,但是其实还是有一些错误,这里先纠正一下。

  1. 以为通过elsticstack实现了默认的分词器 通过查看elasticsearch types的mapping发现string类型的根本就没有加载ik analyzer
  2. 拼音分词方式设置错误 拼音分词的尝试过程中,终于实现了全拼分词

环境搭建

Elasticsearch安装拼音分词:

http://my.oschina.net/UpBoy/blog/625014?fromerr=mRvT8rzk

Django依赖安装:

django-haystack==2.5.dev1

之前会使用elasticstack与haystack2.4配合,发现问题比较多,所以删掉elasticstack,升级haystack为github上的最新版本

Django-Elasticsearch实现搜索功能

在项目中实现了资讯搜索功能,用到了Django Tastypie haystack Elasticsearch ik分词,覆盖了我对搜索了解的所有姿势。其实也就了解一些简单的概念,不过haystack+elasticsearch并不需要太多搜索基础,只要看看haystack文档就就能实现简单的搜索需求了。

搭建Elasticsearch环境

http://www.sojson.com/blog/81

参考以上文档搭建了自己的ES环境,然后再安装Django实现搜索的相关库:

django-haystack==2.4.1
elasticsearch==2.3.0
elasticstack==0.4.1

haystack不用说,在Django中实现搜索基本上都会用到,因为要用到Elasticsearch的BackEnds,所以要装elasticsearch,最后elasticstack会在下面说到。

haystack使用ik分词

在elasticsearch中可以在创建了indexs后可以在settings中自定义analyzer,在创建types时可以设置各个field使用的analyzer,但是在haystack中就比较麻烦了。

https://github.com/django-haystack/django-haystack/issues/639

从上面的issues中可以看出,如果需要解决这个问题,需要重写elasticsearch backends中相关设置,在查看了elasticsearch backends代码后,发现除了DEFAULT_SETTINGS中配置自定义analyzer,DEFAULT_FIELD_MAPPINGFIELD_MAPPINGS分别用于设置field在mapping中analyzer,重写相关配置与方法可达到定义不同字段的分词器。

但是重写配置方法还是太麻烦了,能不能更简单点呢,所以找到了elasticstack,用上了这个工具后,配置默认的analyzer就非常简单了。

HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'elasticstack.backends.ConfigurableElasticSearchEngine',
        'URL': 'http://127.0.0.1:9200/',
        'INDEX_NAME': 'haystack',
    },
}

ELASTICSEARCH_DEFAULT_ANALYZER = 'ik' # 设置默认分词器为ik

Django save方法的update_fields参数

在Django中对Model对象的属性赋值,并使用save方法,save方法并不会检测Model对象变更了什么属性,而是会使用update语句set所有的field为当前的值,也就是说只修改了部分字段,也会update所有字段的值,这样会导致2个问题:

  1. SQL语句过大,导致SQL执行慢(一般也不会有什么影响)
  2. 如果同时操作同一个Model对象,更新不同的字段,后save的操作会用老的值覆盖掉早点操作的值

所以推荐在调用save方法的时候传update_fields参数,但是这样就要求我们必须对每次save的fields都在代码中记下来,不是很方便,所以开发一个通用的专门用来处理update_fields参数的Mixin类来解决这个问题。