简体   繁体   中英

Function comparing two strings slower in nim than python

I am a novice in nim, but want to use it to write functions to use in python. I am using nimpy and nimporter for importing nim functions to python.

This function in python:

def pcompare(a, b):
    letters = []
    for i, letter in enumerate(a):
        if letter != b[i]:
            letters.append(f'{letter}{i}{b[i]}')
    return letters

Returns a list of cases where characters in string a does not match characters in string b .

I wrote the same functions in nim:

compare.nim

import strformat
import nimpy

proc compare(a, b: string): seq[string] {.exportpy.} =
  for i, letter in a:
      if letter != b[i]:
        result.add(fmt"{letter}{i}{b[i]}")

Which i can import to python: import nimporter; import compare; import nimporter; import compare; The functions generates the same output as the python code.

However, the nim function is much slower than the python code!

a = 'aaaa' * 1000000
b = 'bbba' * 1000000

s = time.perf_counter()
ptest = pcompare(a, b)
e = time.perf_counter()
print(e - s)

s = time.perf_counter()
ntest = compare.compare(a, b)
e = time.perf_counter()
print(e - s)

output: 
python: 1.2781826159916818
nim: 3.607558835996315

Can anyone that is fluent in nim or another compiled language explain why this is the case, and perhaps suggest improvement to my nim code?

All comments are much appreciated!

Thanks, William

This is a classic example of compiling without the release switch. If you read the output from when you compiled your Nim module you should see a line like this:

Hint: gc: refc; threads: on; opt: none (DEBUG BUILD, '-d:release' generates faster code)

Compiling with -d:release is essential to get good speed in Nim. Depending on what you're doing you can also get some more (with less runtime checking) with -d:danger , and depending on the workload it might also help to try the new --mm:arc memory management mode.

So let's compare some numbers, on my machine the code you supplied gives these results:

0.9097748600001978
5.580064230000062

Oh no, even worse than your numbers, not great! But if we turn on the -d:release switch the tides turn:

0.9215690670002914
0.5742033299998184

Throwing on -d:danger gives another little boost (compared more samples in my testing, it was consistently slightly faster):

0.9454311069998766
0.5695095589999255

ARC didn't help for this particular workload, and neither did LTO, but both of those might perform better for other things. In general there is a lot you can do to speed up Nim, but by far the easiest and the most efficient is turning on release building.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM