python高手之路 笔记4 性能与优化专题

性能与优化


数据结构

多利用python本身的代码

  • dict.get()示例
#dict.get(key, default=None)
#key -- 这是要搜索在字典中的键。
#default -- 这是要返回键不存在的的情况下默认值。
def get_fruits(basket, fruit):
    return basket.get(fruit, set())
  • set()示例
#集合做差集,判断是否有指定元素之外的元素
def has_invalid_fields(fields):
    return bool(set(fields) - set(['foo', 'bar'])
  • defaultdict()示例
import collections
def add_animal_in_family(species, animal, family):
    species[family].add(animal)
species = collections.defaultdict(set)
add_animal_in_family(species, 'cat', 'felidea')

每次试图从字典中访问一个不存在的元素,defaultdict都会使用作为参数传入的这个函数去构造一个新值而不是抛出KeyError。

性能分析

  • 使用cProfile模块
$ python -m cProfile myscript.py

可以使用-s选项按其他字段进行排序,如-s time

  • C语言分析Valgrind以及可视化工具KCacheGrind

$ python -m cProfile -o myscript.cprof myscript.py
$ pyprof2calltree -k -i myscript.cprof

- dis模块:python字节码的反编译器

#### namedtuple和slots
- python中拥有一些固定属性的简单对象会存储所有的属性在一个字典内,这个字典本身被存在`__dict__`属性中:
```python
class Point(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y
p = Point(1, 2)
p.__dict__
p.z = 42
  • 可以通过__slots__声明来减少内存开销
class Foobar(object):
    __slots__ = 'x'
    def __init__(self, x):
        self.x = x
  • 使用python包 memory_profiler检测内存使用情况
$ python -m memory_profiler object.py

缓存加速技术

  • memoization是指通过缓存函数返回结果来加速函数调用的一种技术。仅当函数是纯函数时结果才可以被缓存,也就是说函数不能有任何副作用或输出,也不能依赖任何全局状态。
  • 基本的memoization技术
import math
_SIN_MEMOIZED_VALUES = {}
def memoized_sin(x):
    if x not in _SIN_MEMOIZED_VALUES:
        _SIN_MEMOIZED_VALUES[x] = math.sin(x)
    return _SIN_MEMOIZED_VALUES[x]
  • 使用functools.lru_cache实现
import functools
import math
@functools.lru_cache(maxsize = 2)
def memoized_sin(x):
    return math.sin(x)

使用后可以使用memoized_sin.cache_info()查看缓存情况

GIL(Global Interpreter Lock, 全局解释器锁)

利用memoryview实现浅拷贝(引用)

  • 使用memoryview可以在内存区域的任何点放入数据
ba = bytearray(8)
ba_at_4 = memoryview(ba)[4:]
#引用bytearray,从其偏移索引4到其结尾
with open("/dev/urandom", "rb") as source:
    source.readinto(ba_at_4)
    #将/dev/urandom的内容写入bytearray中从偏移索引4到结尾的位置,精确且高效地只读写了4字节

多进程与多线程

  • multiprocessing模块不仅可以有效地将负载分散到多个本地处理器上,而且可以通过它的multiprocessing.managers对象在网络中分散负载。它还提供了双向传输,以使进程间可以彼此交换信息。
  • 每次考虑在一定时间内并行处理一些工作时,最好依靠多进程创建(fork)多个作业,以便能够在多个CPU核之间分散负载。

异步和事件驱动架构

  • 事件驱动架构背后的技术是事件循环的建立。程序调用一个函数,它会一直阻塞直到收到事件。其核心思想是令程序在等待输入输出完成前保持忙碌状态,最基本的事件通常类似于“我有数据就绪可被读取”或者“我可以无阻塞地写入数据”
  • 在Unix中,用于构建这种事件循环的标准函数是系统调用select(2)或者poll(2)。它们会对几个文件描述符进行监听,并在其中之一准备好读或写时做出响应。
  • python中有select,asyncio,pyev

面向服务架构

使用ZeroMQ

RDBMS和ORM

SQLAlchemy PostgreSQL

上下文管理器

  • 上下文管理协议:

    1. 调用方法A
    2. 执行一段代码
    3. 调用方法B
  • with (open) as :执行一段代码

  • 这里希望调用方法B必须总是在调用方法A之后。open函数很好地阐明了这一模式,打开文件并在内部分配一个文件描述符的构造函数便是方法A。释放对应文件描述符的close方法就是方法B。显然,close方法总是应该在实例化文件对象之后调用。

  • contextlib标准库提供了contextmanager,通过生成器构造__enter____exit__方法,从而简化了这一机制的实现。

  • 在流水线对象上使用上下文管理器

import contextlib
class Pipeline(object):
    def _publish(self, objects):
        #image publication code here
        pass
    def _flush(self):
        #image flushing code here
        pass
    @contextlib.contextmanager
    def publisher(self):
        try:
            yield self._publish
        finally:
            self._flush()

现在,当用户在使用流水线发布某些数据时,他们无需使用_publish或者_flush。用户只需请求一个使用了名组(eponym)函数的publisher并使用它。

pipeline = Pipeline()
with pipeline.publisher() as publisher:
    publisher([1, 2, 3, 4])
    #当提供这样一个API时,就不会遇到用户错误
  • 通过一条with语句同时打开两个文件
with open("file1", "r") as source, open("file2", "w") as destination:
    destination.write(source.read())
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容

  • Python 面向对象Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对...
    顺毛阅读 4,218评论 4 16
  • 教程地址:python进阶 - 慕课网 python函数式编程 变量可以指向函数: f = absprint(f)...
    竹口小生阅读 555评论 0 2
  • 基础1.r''表示''内部的字符串默认不转义2.'''...'''表示多行内容3. 布尔值:True、False(...
    neo已经被使用阅读 1,673评论 0 5
  • 原本想着这种事不要让大家知道的。后来又一想,你们看看也好。 窦莎,一个较胖的姑娘,看脖子上的颈纹就知道到底有多少肉...
    Camilleeeeee阅读 235评论 2 2
  • ca178c736ba9阅读 108评论 0 1