Author: | yihuang |
---|---|
email: | yi.codeplayer@gmail.com |
company: | 深圳云悦科技 |
IO
请先确定瓶颈在Python代码
pypy
准备用pypy的话,今天说的完全不适用
typedef struct {
PyObject_VAR_HEAD
// 结构体内动态数组
PyObject *ob_item[1];
} PyTupleObject;
typedef struct {
PyObject_VAR_HEAD
// 额外分配的内存空间
PyObject **ob_item;
Py_ssize_t allocated;
} PyListObject;
mutable tuple ?
BAD
for i in range(10):
if i in ('test1', 'test2', 'test3'):
pass
GOOD
t = ('test1', 'test2', 'test3')
for i in range(10):
if i in t:
pass
其他预先计算时机:
局部变量:
def test(a):
a
LOAD_FAST 0
LOAD_FAST i
PyObject *PyEval_EvalCodeEx(...) {
register PyObject **fastlocals;
...
fastlocals = f->f_localsplus;
...
fastlocals[i]
...
模块变量:
a = 1
def test():
a
LOAD_GLOBAL 0
LOAD_GLOBAL 0
PyObject *PyEval_EvalCodeEx(...) {
PyObject *names;
...
names = co->co_names;
...
w = PyTuple_GetItem(names, i);
x = PyDict_GetItem(f->f_globals, w);
if (x == NULL) {
x = PyDict_GetItem(f->f_builtins, w);
if (x == NULL) {
load_global_error:
...
test(1, 2, 3, a=1, b=2)
PyObject *func = LOAD_NAME 'test';
PyObject *args = PyTuple_New(3);
PyTuple_SET_ITEM(args, 0, 1);
PyTuple_SET_ITEM(args, 1, 2);
PyTuple_SET_ITEM(args, 2, 3);
PyObject *kwargs = PyDict_New();
PyDict_SetItem(kwargs, "a", 1);
PyDict_SetItem(kwargs, "b", 2);
PyObject_Call(func, args, kwargs);
...
优化方法:
obj.a
object PyObject_GenericGetAttr(object obj, object name):
# 从class中查找descriptor
descr = PyType_Lookup(Py_TYPE(obj), name)
if PyDescr_IsData(descr):
# 如果是data descriptor,直接使用
return descr.__get__(descr, obj, obj->obj_type)
else:
# 否则使用对象字典
r = obj.__dict__[name]
if r is not None:
return r
elif descr is not None:
# 最后使用 Non-data descriptor
return descr.__get__(...)
class LazyUser(object):
def __get__(self, obj, objtype=None):
value = self.loader(obj, objtype)
# 使用对象字典作为缓存
obj.user = value
return value
>>> req.user
计算...
>>> req.user
从字典中取值
def test(a, b):
return a + b
PyObject *test(PyObject *args) {
PyObject *a = PyTuple_GET_ITEM(args, 0);
PyObject *b = PyTuple_GET_ITEM(args, 1);
return PyNumber_Add(a, b);
}
cdef add(a, b):
return a + b
def test(a, b):
cdef int i
for i in range(100):
add(a, b)
PyObject *test(PyObject *args) {
PyObject *pya = PyTuple_GET_ITEM(args, 0);
PyObject *pyb = PyTuple_GET_ITEM(args, 1);
for(int i=0; i<100; i++) {
add(pya, pyb);
}
}
cdef int add(int a, int b):
return a + b
def test(a, b):
cdef int i
for i in range(100):
add(a, b)
int add(int a, int b) {
return a + b;
}
PyObject *test(PyObject *args) {
PyObject *pya = PyTuple_GET_ITEM(args, 0);
PyObject *pyb = PyTuple_GET_ITEM(args, 1);
int a = __Pyx_PyInt_AsInt(pya);
int b = __Pyx_PyInt_AsInt(pyb);
for(int i=0; i<100; i++) {
add(a, b);
}
}
cdef object int_to_decimal_string(Py_ssize_t n):
cdef char buf[32], *p, *bufend
cdef unsigned long absn
cdef char c = '0'
p = bufend = buf + sizeof(buf)
if n < 0:
absn = 0UL - n
else:
absn = n
...
cdef extern int spam_counter
cdef extern from "foo.h":
int spam_counter
struct spam:
pass
cdef extern from "Python.h":
Py_ssize_t PyByteArray_GET_SIZE(object array)
ctypedef class __builtin__.bytearray [object PyByteArrayObject]:
cdef Py_ssize_t ob_alloc
cdef char *ob_bytes
cdef Py_ssize_t ob_size
cdef class Connection(object):
cdef public int port
cdef public object _sock
cdef send_command(self, tuple args):
self._sock.sendall(
self._pack_command(args))
排除IO的影响
patch_socket.py (http://tinyurl.com/pb3joac)
from patch_socket import run_with_recording
...
run_with_recording(_sock, test)
_sock.start_replay()
cProfile.run('test()', sort='time')
创建heap快照 gc.get_objects()
stats = defaultdict(int)
for o in gc.get_objects():
stats[str(type(o))] += 1
对比heap快照
list: 100 tuple: -40 <class '__main__.Test'>: 1
Q & A