前言:
熟悉我的朋友大多是知道我喜欢python的peewee orm,因为他的源码简单,api使用简单,可扩展性强。可能这事都传出去,所以这段时间连续有两个老铁问我peewee的问题。我想这两个问题还有些代表性,所以干脆简单总结下发个文章。
该文章后续仍在不断更新中, 请移步到原文地址 http://xiaorui.cc/?p=5023
python peewee是否支持异步库?
peewee是否支持异步非阻塞 ? 2.7的话,peewee 是可以跟pymysql gevent配合一起用的, tornado peewee就傻了,各种手段用下来,照样阻塞,话说sqlalchemy也没啥解决方法. 如果你是py 3.5 +,那么可以使用peewee async方案,这样选择的余地就多了, 不管是asyncio、tornado都可以兼容。
python peewee 是否支持多进程 (multiprocessing)
peewee是否支持多进程 ? 我只能说,官方默认是不支持多进程的,多进程需要自己做lazy load懒惰加载。 为什么peewee多进程呢? 这个跟他的实现有直接的关系,像redis-py他抽象了线程和进程的连接池,根据不同的进程pid取不同的池子,就算你是 copy on write子进程,但是会共用redis-py的对象,但因为父子进程pid不同,所以redis-py帮你做了规避。 再问一嘴,peewee为啥就不支持多进程,作者来了句,不建议在多进程下使用peewee,然后就没有然后了.
首先我们要清楚为什么多进程下使用同一个连接对象是有问题的,多一个socket被多个进程去读写send/read buffer,数据会写串,网络两端都是有应用层协议的,你都写串了,还怎么识别包…反之,同理。
不管是peewee还是其他的连接池库,我们都可以利用多实例的方法让连接池支持多进程。 实现的要点就两点,第一点多实例区分进程pid, 第二点,惰性加载…. 不多说,直接扔代码. 这种实现不管是uwsgi,gunicorn,multiprocessing 都是支持的,原理代码已经说清楚了。
# xiaorui.cc import os import redis from peewee import * from playhouse.shortcuts import RetryOperationalError from conf.config import mysql_addr, redis_conf def singleton(cls, *args, **kw): instances = {} def _singleton(): key = str(cls) + str(os.getpid()) if key not in instances: instances[key] = cls(*args, **kw) return instances[key] return _singleton class MyRetryDB(RetryOperationalError, MySQLDatabase): pass @singleton class DB(object): def __init__(self): self.mysql_db = MyRetryDB(host=mysql_addr['host'], port=mysql_addr['port'], user=mysql_addr['user'], passwd=mysql_addr['passwd'], database=mysql_addr['db'], charset='utf8mb4', threadlocals=True) self.redis_queue = redis.Redis(host=redis_conf['host'], port=redis_conf['port'], db=redis_conf['db'])
总结,python3 到现在为止还没出一个绝逼好用且支持异步的orm… gevent + peewee + pymysql 算是无限接近了,可惜python3的时代,再用这组合就显得不伦不类了。
END.