从映射连接字符串时的性能

Posted

技术标签:

【中文标题】从映射连接字符串时的性能【英文标题】:Performance while joining strings from mapping 【发布时间】:2020-09-08 10:36:32 【问题描述】:

我在从映射 (Mapping[str, str]) 连接字符串时查看性能。

我有这两个简单的功能:

def nested(sequence, mapping):
    
    string = ""
    
    for x in sequence:
        
        string += mapping[x]
    
    return string

def flat(sequence, mapping):
    
    return "".join(mapping[x] for x in sequence)

在我的项目中,我发现使用“平面”解决方案时性能明显下降。最初,我选择该解决方案是因为:“平面比嵌套更好。”,但很快就转向了“嵌套”解决方案。

我用更简单的序列和映射进行了 timeit 测试:

letters = (
    "a","b","c","d","e","f","g","h","i","j","k","l","m",
    "n","o","p","q","r","s","t","u","v","w","x","y","z"
)

mymapping = x: x for x in letters

mysequence = "mysequence"

print(timeit.timeit("nested(mysequence, mymapping)", globals=globals()))

print(timeit.timeit("flat(mysequence, mymapping)", globals=globals()))

并获得:

In [683]: 0.675819274969399
0.965234256349504

“嵌套”解决方案的速度提高了 43%。 在我的项目中,我观察到速度快了好几倍的情况。

在文档中,我们可以读到:“连接字符串序列的首选快速方法是调用''.join(sequence)”。但我清楚地看到“+”运算符在此配置中更快。

虽然我没有问题继续使用“嵌套”解决方案:

我是否缺少另一个“平面”解决方案? (没有sum() 可能带有字符串)

你对这种行为有解释吗?

谢谢。

【问题讨论】:

这在很大程度上取决于您要加入的什么。例如,仅 10 个字符的字符串就可以轻松放入各种缓存中,从而抵消大部分成本。比较例如mymapping = x: x*1024 for x in letters. @MisterMiyagi 我发现与您的 mymapping 以及在我的项目中字符串是复杂的正则表达式的性能观察结果相当。我认为它与每个函数在内部的工作方式更相关(参见其他答案中提出的 flat_list 和 remap 函数)。 【参考方案1】:

当你使用列表推导时,我的加入速度更快:

def flat_list(sequence, mapping):
    return "".join([mapping[x] for x in sequence])
2.5292927          # nested
2.3440613999999997 # flat_list
6.530926599999999  # flat

我的猜测是它与this 有关。生成器表达式似乎有一些小的开销,并且重复了 10000 次,这种差异变得可见。

【讨论】:

非常感谢关于生成器表达式的有趣信息!【参考方案2】:

我是否缺少另一个“平面”解决方案? (字符串不能使用 sum())

Josef 的回答看起来不错,所以我只是回应这部分。有一种更优雅的方式(在我看来),它似乎也比其他方法更快。

def remap(sequence, mapping):
    return ''.join(map(mapping.get, sequence))

# mysequence
1.098659     # nested
1.1296278    # flat_list
1.4904282    # flat
0.9128849    # remap

# mysequence * 10
8.5377648    # nested
8.814077     # flat_list
6.1268931    # flat
5.555387     # remap

【讨论】:

有趣,看起来内置类型与map 配合得很好。 这确实是一个优雅的平面解决方案。更有趣的是速度表现!即使我对字节码没有特别的了解,我也查看了所有 4 个函数(@Josef 中的嵌套、平面、平面列表和你的重映射)的字节码(如 @Josef 提供的链接),重映射更简单,其中应该解释一下速度。谢谢!

以上是关于从映射连接字符串时的性能的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Key Vault 自动映射 Azure Functions 机密

使用 DI 连接字符串时的脚手架

连接相邻字符串文字时的 Python 运算符优先级

使用 Database.Create 的对象名称“dbo.__MigrationHistory”无效;传入连接字符串时的EF6.02

前端性能优化:字符串的连接操作改进

提高Java中字符串连接的性能[重复]