Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python中,如何有效地从一个巨大的块中提取具有偏移量的字节?_Python - Fatal编程技术网

在Python中,如何有效地从一个巨大的块中提取具有偏移量的字节?

在Python中,如何有效地从一个巨大的块中提取具有偏移量的字节?,python,Python,假设我有这样一个字节块: block = b'0123456789AB' 我想从4个字节的每个块中提取3个字节的每个序列,并将它们连接在一起。上述区块的结果应为: b'01245689A' # 3, 7 and B are missed 我可以用这样的脚本解决这个问题: block = b'0123456789AB' result = b'' for i in range(0, len(block), 4): result += block[i:i + 3] print(resul

假设我有这样一个字节块:

block = b'0123456789AB'
我想从4个字节的每个块中提取3个字节的每个序列,并将它们连接在一起。上述区块的结果应为:

b'01245689A'  # 3, 7 and B are missed
我可以用这样的脚本解决这个问题:

block = b'0123456789AB'
result = b''
for i in range(0, len(block), 4):
    result += block[i:i + 3]
print(result)

但是众所周知,Python使用for循环和字节连接效率很低,因此如果我将其应用于一个非常大的字节块,我的方法将永远不会结束。那么,有没有更快的执行方法?

使其可变并删除不需要的片段

>>> tmp = bytearray(block)
>>> del tmp[3::4]
>>> bytes(tmp)
b'01245689A'
如果你的块很大,并且你想删除几乎所有的字节,那么收集你想要的可能会更快,就像你的一样。虽然您的应用可能需要二次时间,但最好使用
join

>>> b''.join([block[i : i+3] for i in range(0, len(block), 4)])
b'01245689A'
(顺便说一句,根据它应该是
块[i:i+3]
,而不是
块[i:i+3]
,并且有充分的理由。)

虽然这会生成很多对象,但这可能是内存问题。对于您所陈述的情况,它比您的要快得多,但比我的
bytearray
one慢得多

使用
block=b'0123456789AB'*100_000
进行基准测试(比您在下面的评论中提到的1GB小得多):

基准代码:

import timeit

def baseline(block):
    pass

def original(block):
    result = b''
    for i in range(0, len(block), 4):
        result += block[i:i + 3]
    return result

def Kelly_Bundy_bytearray(block):
    tmp = bytearray(block)
    del tmp[3::4]
    return bytes(tmp)

def Kelly_Bundy_join(block):
    return b''.join([block[i : i+3] for i in range(0, len(block), 4)])

funcs = [
    baseline,
    original,
    Kelly_Bundy_bytearray,
    Kelly_Bundy_join,
    ]

block = b'0123456789AB' * 100_000
args = block,
number = 10**0

expect = original(*args)
for func in funcs:
    print(func(*args) == expect, func.__name__)
print()

tss = [[] for _ in funcs]
for _ in range(3):
    for func, ts in zip(funcs, tss):
        t = min(timeit.repeat(lambda: func(*args), number=number)) / number
        ts.append(t)
        print(*('%8.2f ms ' % (1e3 * t) for t in ts), func.__name__)
    print()

“众所周知”——这真的是你的问题吗?如果是的话,如果性能如此重要的话,也许你不应该用python来做这件事。这可能是你想要的吗?@lucidbrot你会如何使用memoryview来完成这件事?哇!令人印象深刻。这很有效。我在1Gb大小的块上尝试了你的代码,它在我的机器上处理了1秒。非常感谢。如果我在每个块中遗漏了超过1个字节,我应该多次应用
del
?@Fomalhaut-Yes,
del
。除非你有大数据块并且想删除几乎所有的字节,否则其他的可能会更快。@Fomalhaut在答案中添加了更多的内容。谢谢你的研究!在行
b''中加入([block[i:i+3]表示范围内的i(0,len(block),4)])
我建议使用生成器而不是列表,因为内存消耗和性能:
b''。加入(block[i:i+3]表示范围内的i(0,len(block,4))
import timeit

def baseline(block):
    pass

def original(block):
    result = b''
    for i in range(0, len(block), 4):
        result += block[i:i + 3]
    return result

def Kelly_Bundy_bytearray(block):
    tmp = bytearray(block)
    del tmp[3::4]
    return bytes(tmp)

def Kelly_Bundy_join(block):
    return b''.join([block[i : i+3] for i in range(0, len(block), 4)])

funcs = [
    baseline,
    original,
    Kelly_Bundy_bytearray,
    Kelly_Bundy_join,
    ]

block = b'0123456789AB' * 100_000
args = block,
number = 10**0

expect = original(*args)
for func in funcs:
    print(func(*args) == expect, func.__name__)
print()

tss = [[] for _ in funcs]
for _ in range(3):
    for func, ts in zip(funcs, tss):
        t = min(timeit.repeat(lambda: func(*args), number=number)) / number
        ts.append(t)
        print(*('%8.2f ms ' % (1e3 * t) for t in ts), func.__name__)
    print()