Confronti di velocità degli array con Python
Speed comparisons of Python arrays

Versione 1.1 del 23 ottobre 2005
Version 1.1, oct 23 2005

Codice sorgente - source code: python_arrays.zip

Una caratteristica di Psyco non sembra molto nota, ma risulta molto interessante. Può essere trovata anche nella nota 15 di questa pagina:
http://psyco.sourceforge.net/psycoguide/node29.html
Cioè Psyco puo' risultare molto veloce usando il modulo standard array di Python; "molto veloce" puo' significare una velocita' vagamente paragonabile a quella del C. Qui di seguito ci sono dei test.
Si noti che il modo piu' veloce per inizializzare un array poi utilizzabile da Psyco e':
array.array("l",[0])*n

One characteristic of Psyco doesn't seem much known, but it's interesting. It can be found in the note 15 of this page: http://psyco.sourceforge.net/psycoguide/node29.html
it means that Psyco can be very fast using the Python array module of the standard library; "very fast" can mean a speed that can be compared to the C one. Here are some tests.
Note that the faster way to initialize an array that can be used by Psyco is:
array.array("l",[0])*n


import array, psyco, time

def test1(n):
    a = [0] * n
    for i in xrange(n):
        a[i] = i * 2

def test2(n):
    a = array.array("l", [0]) * n
    for i in xrange(n):
        a[i] = i * 2

n = 5000000

t = time.clock()
test1(n)
print round(time.clock()-t, 2)

t = time.clock()
test2(n)
print round(time.clock()-t, 2)

psyco.bind(test1)
psyco.bind(test2)

t = time.clock()
test1(n)
print round(time.clock()-t, 2)

t = time.clock()
test2(n)
print round(time.clock()-t, 2)

import numarray as N
t = time.clock()
a = N.arange(0, n, type=N.Int32)
a *= 2
print round(time.clock()-t, 2)

import Numeric as Nu
t = time.clock()
a = Nu.arange(0, n, typecode="i")
a *= 2
print round(time.clock()-t, 2)



Timing results, n = 5 millions:
7.43 seconds   Python list
10.15 s        Python array
2.51 s         Psyco list
0.74 s         Psyco array
0.84 s         numarray
1.65 s         Numeric
0.33 s         Delphi

In questo esempio giocattolo, Psyco+array è più veloce di numarray e Numeric.

In this toy example, Psyco+array is faster than numarray and Numeric.


Lo stesso esempio con float:

The same example with floats:

import array, psyco, time

def test1(n):
    a = [0.0] * n
    for i in xrange(n):
        a[i] = float(i) * 2

def test2(n):
    a = array.array("d", [0.0]) * n
    for i in xrange(n):
        a[i] = i * 2

n = 2000000

t = time.clock()
test1(n)
print round(time.clock()-t, 2)

t = time.clock()
test2(n)
print round(time.clock()-t, 2)

psyco.bind(test1)
psyco.bind(test2)

t = time.clock()
test1(n)
print round(time.clock()-t, 2)

t = time.clock()
test2(n)
print round(time.clock()-t, 2)

import numarray as N
t = time.clock()
a = N.arange(0.0, n, type=N.Float64)
a *= 2
print round(time.clock()-t, 2)

import Numeric as Nu
t = time.clock()
a = Nu.arange(0.0, n, typecode="d")
a *= 2
print round(time.clock()-t, 2)



Timing results, n = 2 millions:
9.1 seconds   Python list
4.16 s        Python array
4.59 s        Psyco list
0.59 s        Psyco array
0.34 s        numarray
0.88 s        Numeric
0.32 s Delphi

Su questo programma giocattolo, coi float (8 byte) Psyco+array e' più veloce di Numeric, ma quasi due volte piu' lento di numarray. Ma usando Psyco+array c'è comunque il vantaggio che non serve programmazione vettoriale, e la flessibilita' nella programmazione e' maggliore. Comunque Psyco è necessario, altrimenti array e' spesso (stranamente) piu' lento delle liste Python native.

On this toy program, with floats (8 byte) Psyco+array is faster than Numeric, but almost two times slower than numarray. But using Psyco+array there is the advantage that no vector programming is needed, and the programming flexibility is higher. Note that Psyco is necessary, because otherwise array is often slower than normal builtin lists.


Ho anche effettuato gli stessi due testo con Delphi5, con questo programma:

I've also done the same two tests with Delphi5, with this program:

{$APPTYPE CONSOLE}

uses Windows;

procedure test1(n: integer);
  var
    a: array of integer;
    i: integer;
  begin
    SetLength(a, n);
    for i:= 0 to n-1 do
        a[i]:= i * 2;
  end;


procedure test1fp(n: integer);
  var
    a: array of double;
    i: integer;
  begin
    SetLength(a, n);
    for i:= 0 to n-1 do
        a[i]:= i * 2;
  end;


var
  Start, Stop:  DWORD;
  n: integer;
begin
  n:= 5000000;
  Start := GetTickCount;
  test1(n);
  Stop := GetTickCount; writeln( (Stop-Start)/1000:1:3, ' s' );

  n:= 2000000;
  Start := GetTickCount;
  test1fp(n);
  Stop := GetTickCount; writeln( (Stop-Start)/1000:1:3, ' s' );

  readln;
end.

Ecco un'altro test, meno giocattoloso, con una procedura molto veloce per calcolare i primi. La versione A usa un array.

Here is another , less toyish, test with a very fast primes computint routine. The A version uses an array.


import psyco, array, time

def primes(n):
   "primes(n): return a list of prime numbers <=n."

   if n == 2:
       return [2]
   elif n<2:
       return []
   s = range(3, n+2, 2)
   mroot = n ** 0.5
   #mroot = sqrt(n)
   half = len(s)
   i = 0
   m = 3
   while m <= mroot:
       if s[i]:
           j = (m*m - 3) / 2
           s[j] = 0
           while j < half:
               s[j] = 0
               j += m
       i += 1
       m = 2 * i + 3
   if s[-1] > n:
       s[-1] = 0
   return [2] + [x for x in s if x]


def primesA(n):
   "primes(n): return a list of prime numbers <=n."

   if n == 2:
       return [2]
   elif n<2:
       return []
   #s = range(3, n+2, 2)
   #s = array.array("i", [0]) * n
   s = array.array("i", range(3, n+2, 2))
   mroot = n ** 0.5
   #mroot = sqrt(n)
   half = len(s)
   i = 0
   m = 3
   while m <= mroot:
       if s[i]:
           j = (m*m - 3) / 2
           s[j] = 0
           while j < half:
               s[j] = 0
               j += m
       i += 1
       m = 2 * i + 3
   if s[-1] > n:
       s[-1] = 0
   return [2] + [x for x in s if x]


def init(n):
   s = range(3, n+2, 2)

def initA(n):
   s = array.array("i", range(3, n+2, 2))


n = 1000000

t = time.clock()
primes(n)
print round(time.clock()-t, 2), "s"

t = time.clock()
primesA(n)
print round(time.clock()-t, 2), "s"
print

psyco.bind(primes)
psyco.bind(primesA)

t = time.clock()
primes(n)
print round(time.clock()-t, 2), "s"

t = time.clock()
primesA(n)
print round(time.clock()-t, 2), "s"
print

psyco.bind(init)
psyco.bind(initA)

t = time.clock()
init(n)
print round(time.clock()-t, 2), "s"

t = time.clock()
initA(n)
print round(time.clock()-t, 2), "s"



Timing results, n = 1 million:
1.83 s  lists
3.03 s  array

1.0 s   Psyco list
1.57 s  Psyco array


0.55 s  Psyco list just init
1.13 s  Psyco array just init (better to use range instead of xrange

Per questo programma pare che Psyco sulle liste incorporate sia più veloce, il che mi pare strano. Forse il programma contiene qualche parte lenta della quale non mi sono accorto, ma non riesco a trovarla.

But for this program psyco on builtin lists seems faster, this is strange. Maybe I've done something slow, but I cannot find it.


Per confronto ho ripetuto il test col compilatore Python ShedSkin:

For comparison this is a test done with the ShedSkin Python compiler:

http://sourceforge.net/projects/shedskin/
http://shed-skin.blogspot.com/


import time

def primes(n):
   "primes(n): return a list of prime numbers <=n."
   if n == 2:
       return [2]
   elif n<2:
       return []
   s = range(3, n+2, 2)
   half = len(s)
   mroot = n ** 0.5
   i = 0
   m = 3
   while m <= mroot:
       if s[i]:
           j = (m*m - 3) / 2
           s[j] = 0
           while j < half:
               s[j] = 0
               j += m
       i += 1
       m = 2 * i + 3
   if s[-1] > n:
       s[-1] = 0
   return [2] + [x for x in s if x]


n = 1000000
t = time.clock()
primes(n)
print round(time.clock()-t, 2), "s"


Timing results, n = 1 million:
ShedSkin: 0.34 s.
Codice sorgente - source code: python_arrays.zip