Rendimiento de cadena: Python 2.7 frente a Python 3.4 bajo Windows 10 vs. Ubuntu

Caso de uso
Una función simple que verifica si una cadena específica está en otra cadena en una posición que es un múltiplo de 3 (vea aquí para ver unejemplo del mundo real, encontrar codones de parada en una secuencia de ADN).

Las funciones
sliding_window: toma una cadena de longitud 3 y la compara con la cadena de búsqueda; si son idénticos, avanza 3 caracteres.
incremental_start: intenta encontrar la cadena de búsqueda, si la posición encontrada no es múltiplo de 3, intenta encontrar la siguiente posición después de la posición encontrada.

Tenga en cuenta: los datos de muestra son solo para asegurarse de que cada función tiene que pasar por la cadena completa, el rendimiento es similar con datos reales o datos aleatorios.

Resultados

Python 2.7: La inicialsliding_window la función podría mejorarse en un factor de ~ 39 utilizando la funciónincremental_start en Python2.7 en Windows 10. Hubo una ligera caída en la mejora del rendimiento en Ubuntu, ~ 34x, ~ 37x, ~ 18x (VM, AWS, nativo), pero aún en el mismo rango.
Python 3.4: sliding_window se hizo más lento que en Python2.7 (1.8x en Windows, 1.4x y 1.5x en todos los Ubuntus), pero elincremental_start el rendimiento se redujo en todos los Ubuntus por un factor de 4, 5, 1.7 (VM, AWS, nativo), mientras que apenas cambió en Windows, s.Windows vs Ubuntu
Python2.7: Ubuntus virtualizado necesitaba menos tiempo para ambas funciones (~ 20-30%), Ubuntu nativo era aproximadamente un 25% más lento paraincremental_start, mientrassliding_window fue 40% más rápido
Python3: elsliding_window la función necesitaba menos tiempo para finalizar (~ 50%), mientras que la funciónincremental_start se hizo más lento por un factor de ~ 2-3.

Preguntas

¿Qué causa la diferencia de rendimiento en Python 2 vs. Python 3 en Linux vs. Windows?¿Cómo es posible anticipar tal comportamiento y ajustar el código para un rendimiento óptimo?

Código

import timeit

text = 'ATG' * 10**6
word = 'TAG'

def sliding_window(text, word):
    for pos in range(0, len(text), 3):
        if text[pos:pos + 3] == word:
            return False
    return True

def incremental_start(text, word):
    start = 0
    while start != -1:
        start = text.find(word, start + 1)
        if start % 3 == 0:
            return False
    return True

#sliding window
time = timeit.Timer(lambda: sliding_window(text, word), setup='from __main__ import text, word').timeit(number=10)
print('%3.3f' % time)

#incremental start
time = timeit.Timer(lambda: incremental_start(text, word), setup='from __main__ import text, word').timeit(number=500)
print('%3.3f' % time)

Mesas

Ubuntu vs Windows    VM     AWS    Native   
Python2.7-Increment  79%    73%    126% 
Python2.7-Sliding    70%    70%    60%                  
Python3.4-Increment  307%   346%   201% 
Python3.4-Sliding    54%    59%    48%  

Py2 vs 3    Windows    VM    AWS    Native
Increment   105%       409%  501%   168%
Sliding     184%       143%  155%   147%

Absolute times in seconds
                 Win10   Ubuntu  AWS     Native
Py2.7-Increment  1.759   1.391   1.279   2.215 
Py2.7-Sliding    1.361   0.955   0.958   0.823 

Py3.4-Increment  1.853   5.692   6.406   3.722 
Py3.4-Sliding    2.507   1.365   1.482   1.214 

Detalles
Windows 10: Windows nativo, 32 bits Python 3.4.3 o 2.7.9, i5-2500, 16 GB de RAM
Máquina virtual Ubuntu: 14.04, se ejecuta en el host de Windows, Python 3.4.3 de 64 bits, Python 2.7.6, 4 núcleos, 4 GB de RAM
AWS: 14.04, microinstancia AWS, 64 bit Python 3.4.3, Python 2.7.6
Ubuntu nativo: 14.04, 64 bit Python 3.4.3, Python 2.7.6, i5-2500, 16 GB de ram [idéntico a la máquina Win10]

Actualizar

Según lo sugerido por Ingazxrange ybytes se utilizaron, una ligera mejora en el rendimiento pero una caída masiva en el rendimiento en Ubuntu con Python3.4. El culpable parece serfind que es mucho más lento cuando se combinan Ubuntu y Py3.4 (lo mismo con Py3.5 que se compiló desde la fuente). Esto parece depender del sabor de Linux, en Debian Py2.7 y Py3.4 se realizó idéntico, en RedHat Py2.7 fue considerablemente más rápido que Py3.4.
Para una mejor comparación, Py3.4 ahora se usa en 64 bits en Windows10 y Ubuntu. Py27 todavía se usa en Win10.

import timeit, sys

if sys.version_info >= (3,0):
    from builtins import range as xrange

def sliding_window(text, word):
    for pos in range(0, len(text), 3):
        if text[pos:pos + 3] == word:
            return False
    return True

def xsliding_window(text, word):
    for pos in xrange(0, len(text), 3):
        if text[pos:pos + 3] == word:
            return False
    return True

def incremental_start(text, word):
    start = 0
    while start != -1:
        start = text.find(word, start + 1)
        if start % 3 == 0:
            return False
    return True

text = 'aaa' * 10**6
word = 'aaA'
byte_text = b'aaa' * 10**6
byte_word = b'aaA'

time = timeit.Timer(lambda: sliding_window(text, word), setup='from __main__ import text, word').timeit(number=10)
print('Sliding, regular:      %3.3f' % time)

time = timeit.Timer(lambda: incremental_start(text, word), setup='from __main__ import text, word').timeit(number=500)
print('Incremental, regular:  %3.3f' % time)

time = timeit.Timer(lambda: sliding_window(byte_text, byte_word), setup='from __main__ import byte_text, byte_word').timeit(number=10)
print('Sliding, byte string:  %3.3f' % time)

time = timeit.Timer(lambda: incremental_start(byte_text, byte_word), setup='from __main__ import byte_text, byte_word').timeit(number=500)
print('Incremental, bytes:    %3.3f' % time)

time = timeit.Timer(lambda: xsliding_window(byte_text, byte_word), setup='from __main__ import byte_text, byte_word').timeit(number=10)
print('Sliding, xrange&bytes: %3.3f' % time)

time = timeit.Timer(lambda: text.find(word), setup='from __main__ import text, word').timeit(number=1000)
print('simple find in string: %3.3f' % time)


Win10-py27  Wi10-py35   VM-py27  VM-py34
1.440       2.674       0.993    1.368 
1.864       1.425       1.436    5.711 
1.439       2.388       1.048    1.219 
1.887       1.405       1.429    5.750 
1.332       2.356       0.772    1.224 
3.756       2.811       2.818    11.361 

Respuestas a la pregunta(1)

Su respuesta a la pregunta