0

I tested the codes below with the time function of Bash.
Why is a list comprehension not fast in PyPy3, although it is the fastest in CPython to create a list?
Is this because some optimizations are implemented in PyPy3 for the index-access?

# test_list_compr.py
import os


def main():
    n = 10 ** 8
    lis = [i * 2 for i in range(n)]
    print(sum(lis), file=open(os.devnull, mode="w"))


if __name__ == "__main__":
    main()
# test_list_for.py
import os


def main():
    n = 10 ** 8
    lis = []
    for i in range(n):
        lis.append(i * 2)
    print(sum(lis), file=open(os.devnull, mode="w"))


if __name__ == "__main__":
    main()
# test_list_index.py
import os


def main():
    n = 10 ** 8
    lis = [0] * n
    for i in range(n):
        lis[i] = i * 2
    print(sum(lis), file=open(os.devnull, mode="w"))


if __name__ == "__main__":
    main()
Results:
python3 test_list_compr.py  8.09s user 2.10s system 96% cpu 10.522 total
python3 test_list_for.py  11.62s user 1.76s system 89% cpu 15.009 total
python3 test_list_index.py  9.46s user 1.56s system 89% cpu 12.316 total

pypy3 test_list_compr.py  2.51s user 2.27s system 87% cpu 5.445 total
pypy3 test_list_for.py  2.39s user 2.17s system 99% cpu 4.603 total
pypy3 test_list_index.py  0.49s user 0.19s system 98% cpu 0.694 total

Env:
CPython3 (3.8.2), PyPy3 (7.3.0)

Update
Following mattip's comment, I updated PyPy3 to v7.3.1, and the list comprehension's performance significantly improves.
I appreciate the PyPy developers!

Results:
pypy3 test_list_compr.py  0.54s user 0.27s system 97% cpu 0.830 total
pypy3 test_list_for.py  2.74s user 2.49s system 94% cpu 5.530 total
pypy3 test_list_index.py  0.53s user 0.27s system 71% cpu 1.115 total
solzard
  • 93
  • 1
  • 5
  • Your `for` code is extending the list one at a time, whereas the ‘index’ method does a bulk creation of the list. But anyway why does this level of detail about timing matter? – DisappointedByUnaccountableMod Apr 10 '20 at 19:21
  • This code is actually a part of a data structure, and other codes replace i * 2 or sum(lis). Because I'm a competitive programmer and time limits in most problems are 2-3s, the difference in 0.1s matters to me. – solzard Apr 10 '20 at 19:35
  • 1
    The JIT cannot warm up on a single run. What happens if you run main() 2000 times? Also: please try the latest release (7.3.1), we improved exactly this use case – mattip Apr 11 '20 at 17:44
  • Thank you mattip! In 7.3.1, a list comprehension really works fast. – solzard Apr 12 '20 at 03:03

1 Answers1

0

As stated in the Update part of the question, a list comprehension works fast in 7.3.1.

solzard
  • 93
  • 1
  • 5