通常在我们在编写 Python 程序的时候,需要什么库我们就直接用 pip 安装了,这种情况下是全局式的安装。我们在创建一个 Python 项目的时候,例如有的项目需要 Python3,有的需要 Python2,为了避免项目依赖的互相影响以及去除不需要的库,通常会通过虚拟环境来解决。
这个虚拟环境其实相当于另外独立出一个 Python 环境,有自己的独立的库,独立的依赖关系,是在开发项目时候的利器。话不多说,下面讲一下使用方法。
通常在我们在编写 Python 程序的时候,需要什么库我们就直接用 pip 安装了,这种情况下是全局式的安装。我们在创建一个 Python 项目的时候,例如有的项目需要 Python3,有的需要 Python2,为了避免项目依赖的互相影响以及去除不需要的库,通常会通过虚拟环境来解决。
这个虚拟环境其实相当于另外独立出一个 Python 环境,有自己的独立的库,独立的依赖关系,是在开发项目时候的利器。话不多说,下面讲一下使用方法。
1 | l1 =[1,2,3] |
1 | # |
列表解析更好,时间更短。
1 | # coding:utf-8 |
1 | dictdata = {x: randint(0, 100) for x in xrange(0, 50)} |
1 | setdata = set(data) |
1 | from random import randint |
1 | from collections import namedtuple |
问题:
1 | from random import randint |
1 | from random import randint, sample |
问题:按照创建元素的顺序创建字典
1 | # 一个简单的竞赛排名系统 |
1 | from random import randint |
参考:https://nvie.com/posts/iterators-vs-generators/
可迭代对象需要通过 iter () 方法实现为迭代器,然后才能通过 next() 迭代。
生成器是特殊(优雅)的迭代器(通过 yield 方法实现迭代器)。
一句话就是,只有迭代器对象才可以迭代,可迭代对象的意思就是可以实现为迭代器对象,然后迭代,生成器就是迭代器。
可迭代对象接口:__iter__(),__getitem__(),__next__()
迭代器对象接口:next()
1 | from collections import Iterable, Iterator |
1 | class PrimeNumbers: # 生成器实现可迭代对象 |
问题:实现一个浮点数发生器,根据范围和步长迭代
引子:如何将列表反向?
1 | l = [1, 2, 3, 4, 5] |
1 | class FloatFange: |
问题:有某个文本文件,我们想读取其中某范围的内容,如 100-300 行的内容
1 | from itertools import islice |
问题:
1 | from random import randint |
问题:s = ‘ab;cd,|enf|def,kdjk;kdjfk\dd’ 有多种分隔符,如何处理
1 | import re |
问题:某文件目录下有一系列文件,例如 .c,.py,.js
1 | import os, stat |
问题:例如需要更改 log 文件中的日期表示形式
1 | import re |
问题:
1 | s1 = 'ddjfaljfl;' |
问题:
1 | s.ljust(20) |
1 | # 去掉字符串两端的字符 |
关于 python 的编解码,看这一篇就够了:https://foofish.net/why-python-encoding-is-tricky.html
1 | s = u'你好' |
二进制文件,例如:视频,图片,录音等。
大小端字节
参考:https://blog.csdn.net/hnlyyk/article/details/52541923
大端:低地址存放高字节位
小端:低地址存放低字节位
1 | import struct |
问题:
1 | f = open('demo.txt','w',buffering=2048) # 全缓冲,默认 4096B |
1 | import mmap |
1 | import os, stat |
1 | from tempfile import TemporaryFile, NamedTemporaryFile |
1 | import csv |
1 | from record import Record # 录音模块 |
1 | import json |
1 | from xml.etree import ElementTree |
1 | from xml.etree.ElementTree import Element, ElementTree |
1 | import csv |
1 | # coding:utf-8 |
普通的实例创建完成之后,会有一个 __dict__ 方法,这个方法可以动态绑定实例,但是也造成了很大的内存开销,所以可以通过 __slot__ 属性,阻止动态绑定实例
1 | # 在类中实现 |
问题:不想让用户通过属性来管理,形式上是使用属性访问,实际上调用方法
1 | from math import pi |
1 | # 第一种方法,挨个实现 |
要求:
1 | class Attr(object): |
1 | import weakref |
1 | # 第一种方法 |
1 | from threading import Thread |
1 | from Queue import Queue |
1 | from threading import Event, Thread |
1 | # coding:utf-8 |
参考:https://foofish.net/python-decorator.html
使用装饰器极大地复用了代码,但是他有一个缺点就是原函数的元信息不见了,比如函数的docstring
、__name__
、参数列表,先看例子:
1 | # 装饰器 |
1 | from functools import wraps |
装饰器还有更大的灵活性,例如带参数的装饰器,在上面的装饰器调用中,该装饰器接收唯一的参数就是执行业务的函数 foo 。装饰器的语法允许我们在调用时,提供其它参数,比如@decorator(a)
。这样,就为装饰器的编写和使用提供了更大的灵活性。比如,我们可以在装饰器中指定日志的等级,因为不同业务函数可能需要的日志级别是不一样的。
1 | def use_logging(level): |
上面的 use_logging 是允许带参数的装饰器。它实际上是对原有装饰器的一个函数封装,并返回一个装饰器。我们可以将它理解为一个含有参数的闭包。当我 们使用@use_logging(level="warn")
调用的时候,Python 能够发现这一层的封装,并把参数传递到装饰器的环境中。
@use_logging(level="warn")
等价于@decorator
1 | from functools import wraps |
python 中的单例模式有四种实现方式:
__new__
方法这里解释使用 __new__
方法的实现。
1 | # coding:utf-8 |
1 | # -*- coding:utf-8 -*- |
1 | # coding:utf-8 |
1 | # -*- coding:utf-8 -*- |
1 | # -*- coding:utf-8 -*- |
1 | class ListNode: |
1 | # coding:utf-8 |
1 | ''' |
1 | # -*- coding:utf-8 -*- |
1 | # -*- coding:utf-8 -*- |
1 | # coding:utf-8 |
1 | # -*- coding:utf-8 -*- |
1 | # -*- coding:utf-8 -*- |
1 | # coding:utf-8 |
1 | # -*- coding:utf-8 -*- |
NOOP 全称 No Operation,中文名称电梯式调度器,该算法实现了最简单的 FIFO 队列,所有 I/O 请求大致按照先来后到的顺序进行操作。之所以说”大致“,原因是 NOOP 在 FIFO 的基础上还做了相邻 IO 请求的合并,并不是完完全全按照先进先出的规则满足 IO 请求。它是基于先入先出(FIFO)队列概念的 Linux 内核里最简单的 I/O 调度器。此调度程序最适合于固态硬盘。
Anticipatory 的中文含义是”预料的,预想的”,顾名思义有个 I/O 发生的时候,如果又有进程请求 I/O 操作,则将产生一个默认的 6 毫秒猜测时间,猜测下一个进程请求 I/O 是要干什么的。这个 I/O 调度器对读操作优化服务时间,在提供一个 I/O 的时候进行短时间等待,使进程能够提交到另外的 I/O。Anticipatory 算法从 Linux 2.6.33 版本后被删除了,因为使用 CFQ 通过配置也能达到 Anticipatory 的效果。
Deadline 翻译成中文是截止时间调度器,它避免有些请求太长时间不能被处理。另外可以区分对待读操作和写操作。DEADLINE 额外分别为读 I/O 和写 I/O 提供了 FIFO 队列。
CFQ 全称 Completely Fair Scheduler ,中文名称完全公平调度器,它是现在许多 Linux 发行版的默认调度器,CFQ 是内核默认选择的 I/O 调度器。该算法的特点是按照 IO 请求的地址进行排序,而不是按照先来后到的顺序来进行响应。CFQ 为每个进程/线程,单独创建一个队列来管理该进程所产生的请求,也就是说每个进程一个队列,各队列之间的调度使用时间片来调度,
1 | [sankuai@dx-cloud-climc01 ~]$ dmesg | grep -i scheduler |
1 | [sankuai@gh-cloud-mss-store02 ~]$ cat /sys/block/sda/queue/scheduler |
1 | yum -y install kernel-doc |
1 | $ grubby --grub --update-kernel=ALL --args="elevator=deadline |
1 | 使用vi编辑器修改grub配置文件 |
1 | [sankuai@gh-cloud-mss-store02 ~]$ ls -l /sys/block/sda/queue/iosched |
back_seek_max
默认 16384。该参数规定了磁头向后寻址的最大范围,默认值是16M。对于请求所访问的扇区号在磁头后方的请求,cfq 会像向前寻址的请求一样调度他。
back_seek_penalty
默认值是 2。该参数用来计算向后寻址的代价。相对于前方查找,后方查找的距离为 1/2(1/back_seek_penalty)时,cfq 调度时就认为这两个请求寻址的代价是相同的。
fifo_expire_async
默认值是250ms。该参数用来控制异步请求的超时时间。如果队列被激活后,则优先检查是否有请求超时,如果有超时的请求,则派发。但是,在队列激活的期间内,只会派发 一个超时的请求,其余的请求按照请求的优先级,以及所访问的扇区号大小来派发。
fifo_expire_sync
默认值是125ms。功能类似于fifo_expire_async参数,该参数用于控制同步请求的超时时间,。
group_idle
默认值是 8ms,该参数为了提高吞吐量。
group_isolation
该参数用来标识应用程序所在的cgroup。
low_latency
该参数用来表示低延迟,默认值是1ms
quantum
该参数用于控制队列派发到设备驱动层所含有的请求数,默认值是8。不管是同步队列还是异步队列, 在时间片内,超过这个限制,则不再派发请求。对于异步队列 而言,请求数的派发个数还取决于参数slice_async_rq。
slice_async
默认值是 40ms。这个参数功能同slice_sync,但是用来计算异步队列的时间片。
异步队列的时间片的计算公式是:time slice=slice_async + (slice_async/5 * (4 - priority));
slice_async_rq
默认值是 2。这个参数用来计算在时间片内异步请求被派发的最大数。同样,最大请求数也依赖于队列的优先级。计算公式是:最大请求数=2 * slice_async_rq( 8 –priority );
slice_idle
默认值是 8ms,这个参数只控制同步队列的idle time。当同步队列当前没有请求派发时,并不切换到其他队列,而是等待 8ms,以便让应用程序产生更多的请求。直到同步队列的时间片用完。
slice_sync
默认值是 100ms。这个参数用来计算同步队列的时间片, 默认值是100ms。时间片还依赖于队列的优先级。同步队列的时间片的计算公式是:time slice=slice_sync + (slice_sync/5 * (4 - priority));
1 | The parameters are: |
可以使用专业的工具 fio,或者命令 dd。
fio 可以采用命令行格式,也可以采用 jobfile 格式。
1 | fio [options] [jobfile] ... |
1 | runtime=time 单位:seconds |
1 | direct=bool # 是否使用缓存,true 表示不使用缓存 |
1 | blocksize/bs=int[,int][,int] # read, writes, trimes,默认是 4096 |
1 | iomem=str, mem=str |
1 | size=int # 一个任务中每一个线程的总大小 |
1 | ioengine=str |
1 | iodepth=int # 线程的数量 |
1 | thinktime=time # I/O 发出后,在一段时间内停止,再发出下一个 |
1 | latency_target=time # 如果设置,fio将尝试查找给定工作负载运行时的最高性能点,同时保持低于此目标的延迟。 |
1 | write_iolog=str |
1 | thread # fio 默认是通过 fork 的方式创建任务,但是如果这个参数指定,就会采用 POSIX 的线程函数来创建线程 |
1 | verify_only # 不指定工作负载,只验证数据是否符合之前的 |
1 | steadystate=str:float, ss=str:float # 定义评估稳态性能的标准和限制。 |
1 | write_bw_log=str |
1 | [Rand_Read_Testing] |
参考:http://devopslinux.com/2016/07/23/PTE-fio/
1 | #顺序读 |
1 | [randrw] |
参考:
https://www.ibm.com/developerworks/cn/linux/l-lo-io-scheduler-optimize-performance/index.html