四时宝库

程序员的知识宝库

Cpython源码阅读14-bytes对象合并要使用join

我们上一篇学习了两个字节序列对象进行相加“+”,concat这个函数的底层实现原理。我们看一下当有三个字节序列对象是如何相加的。因为字节对象是不可变对象,不可变对象在进行运算时会再创建一个新的不可变对象。例如有是三个bytes对象进行相加,bytes_result = a+b+c,执行步骤是这样的,临时对象t = a+b, 然后bytes_result = t + c。在这个过程中,a,b的数据被拷贝了两遍。

bytes_result = b''
for bytes_str in bytes_list:
    bytes_result += bytes_str

写出上边这段代码,我们计算一下,假设上边这段代码合并了n个bytes对象,头两个对象需要拷贝n-1次,只有最后一个对象不需要重复拷贝。

这是一种效率非常低下的做法,运算过程中涉及了大量临时对象的调度的创建和销毁,后面我们学习的字符串也是这个道理。官方文档推介使用内建join方法,字节序列和字符串都可以对一个列表进行join,将列表里边的多个字节序列或者字符串join在一起。

bytes_result = b''.join(bytes_str  for bytes_str in bytes_list)

join对数据拷贝进行了优化,先遍历待合并对象,计算总长度;然后根据总长度创建目标对象,逐一拷贝对象。通过这个方法,每个对象只需要拷贝一次,不需要重复拷贝。



/*Concatenate any number of bytes objects.
//连接任意数量的字节对象
The bytes whose method is called is inserted in between each pair.
//调用join方法的字节被插入到每对字节之间
The result is returned as a new bytes object.
//结果作为一个新的bytes对象返回
Example: b'.'.join([b'ab', b'pq', b'rs']) -> b'ab.pq.rs'.*/
//这个例子非常好,说明用b''来调用join实现了字节序列合并
static PyObject *
bytes_join(PyBytesObject *self, PyObject *iterable_of_bytes)
{
    return stringlib_bytes_join((PyObject*)self, iterable_of_bytes);
}

字节序列缓冲池,类似于我们前边说的浮点型空闲对象缓冲池,小整形对象缓冲池,这个可以叫做单字节对象缓冲池。cpython 内部创建单字节bytes对象时,先查看是否该字节对象已经在单字节对象缓冲池。程序刚开始运行时,单字节缓冲池是空的。随着单字节bytes对象的创建,缓冲池中才有了对象。后续再次使用时,直接从缓冲池去,避免重复创建和销毁。

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接