性能與優(yōu)化
數(shù)據(jù)結(jié)構(gòu)
多利用python本身的代碼
- dict.get()示例
#dict.get(key, default=None)
#key -- 這是要搜索在字典中的鍵粟焊。
#default -- 這是要返回鍵不存在的的情況下默認(rèn)值鳍烁。
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都會使用作為參數(shù)傳入的這個函數(shù)去構(gòu)造一個新值而不是拋出KeyError察郁。
性能分析
- 使用cProfile模塊
$ python -m cProfile myscript.py
可以使用-s選項按其他字段進(jìn)行排序伙菜,如-s time
- C語言分析Valgrind以及可視化工具KCacheGrind
$ python -m cProfile -o myscript.cprof myscript.py
$ pyprof2calltree -k -i myscript.cprof
- dis模塊:python字節(jié)碼的反編譯器
#### namedtuple和slots
- python中擁有一些固定屬性的簡單對象會存儲所有的屬性在一個字典內(nèi)轩缤,這個字典本身被存在`__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__
聲明來減少內(nèi)存開銷
class Foobar(object):
__slots__ = 'x'
def __init__(self, x):
self.x = x
- 使用python包
memory_profiler
檢測內(nèi)存使用情況
$ python -m memory_profiler object.py
緩存加速技術(shù)
- memoization是指通過緩存函數(shù)返回結(jié)果來加速函數(shù)調(diào)用的一種技術(shù)。僅當(dāng)函數(shù)是純函數(shù)時結(jié)果才可以被緩存贩绕,也就是說函數(shù)不能有任何副作用或輸出火的,也不能依賴任何全局狀態(tài)。
- 基本的memoization技術(shù)
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實現(xiàn)
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實現(xiàn)淺拷貝(引用)
- 使用memoryview可以在內(nèi)存區(qū)域的任何點放入數(shù)據(jù)
ba = bytearray(8)
ba_at_4 = memoryview(ba)[4:]
#引用bytearray淑倾,從其偏移索引4到其結(jié)尾
with open("/dev/urandom", "rb") as source:
source.readinto(ba_at_4)
#將/dev/urandom的內(nèi)容寫入bytearray中從偏移索引4到結(jié)尾的位置馏鹤,精確且高效地只讀寫了4字節(jié)
多進(jìn)程與多線程
- multiprocessing模塊不僅可以有效地將負(fù)載分散到多個本地處理器上,而且可以通過它的multiprocessing.managers對象在網(wǎng)絡(luò)中分散負(fù)載娇哆。它還提供了雙向傳輸湃累,以使進(jìn)程間可以彼此交換信息勃救。
- 每次考慮在一定時間內(nèi)并行處理一些工作時,最好依靠多進(jìn)程創(chuàng)建(fork)多個作業(yè)治力,以便能夠在多個CPU核之間分散負(fù)載蒙秒。
異步和事件驅(qū)動架構(gòu)
- 事件驅(qū)動架構(gòu)背后的技術(shù)是事件循環(huán)的建立。程序調(diào)用一個函數(shù)宵统,它會一直阻塞直到收到事件晕讲。其核心思想是令程序在等待輸入輸出完成前保持忙碌狀態(tài),最基本的事件通常類似于“我有數(shù)據(jù)就緒可被讀取”或者“我可以無阻塞地寫入數(shù)據(jù)”
- 在Unix中马澈,用于構(gòu)建這種事件循環(huán)的標(biāo)準(zhǔn)函數(shù)是系統(tǒng)調(diào)用select(2)或者poll(2)瓢省。它們會對幾個文件描述符進(jìn)行監(jiān)聽,并在其中之一準(zhǔn)備好讀或?qū)憰r做出響應(yīng)箭券。
- python中有select净捅,asyncio疑枯,pyev
面向服務(wù)架構(gòu)
使用ZeroMQ
RDBMS和ORM
SQLAlchemy PostgreSQL
上下文管理器
-
上下文管理協(xié)議:
- 調(diào)用方法A
- 執(zhí)行一段代碼
- 調(diào)用方法B
with (open) as :執(zhí)行一段代碼
這里希望調(diào)用方法B必須總是在調(diào)用方法A之后辩块。open函數(shù)很好地闡明了這一模式,打開文件并在內(nèi)部分配一個文件描述符的構(gòu)造函數(shù)便是方法A荆永。釋放對應(yīng)文件描述符的close方法就是方法B废亭。顯然,close方法總是應(yīng)該在實例化文件對象之后調(diào)用具钥。
contextlib標(biāo)準(zhǔn)庫提供了contextmanager豆村,通過生成器構(gòu)造
__enter__
和__exit__
方法,從而簡化了這一機(jī)制的實現(xiàn)骂删。在流水線對象上使用上下文管理器
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()
現(xiàn)在掌动,當(dāng)用戶在使用流水線發(fā)布某些數(shù)據(jù)時,他們無需使用_publish或者_(dá)flush宁玫。用戶只需請求一個使用了名組(eponym)函數(shù)的publisher并使用它粗恢。
pipeline = Pipeline()
with pipeline.publisher() as publisher:
publisher([1, 2, 3, 4])
#當(dāng)提供這樣一個API時,就不會遇到用戶錯誤
- 通過一條with語句同時打開兩個文件
with open("file1", "r") as source, open("file2", "w") as destination:
destination.write(source.read())