Migrazione a Python 2.7

Questa pagina descrive le misure necessarie per eseguire l'upgrade dell'applicazione Python al runtime di Python 2.7. Dopo aver seguito questa procedura dettagliata, la tua applicazione può sfruttare le numerose nuove funzionalità del runtime Python 2.7, tra cui il multithreading, il motore di modelli Jinja2, l'accesso e il caricamento del bytecode e diverse nuove librerie di terze parti incluse.

Prerequisiti e considerazioni

Per utilizzare Python 2.7, un'applicazione deve soddisfare i seguenti requisiti:

  • Se l'applicazione utilizza Django, deve utilizzare la versione 1.2 o successive. Per informazioni dettagliate sull'upgrade, consulta la documentazione di Django.
  • Se vuoi utilizzare richieste simultanee, l'applicazione deve utilizzare i gestori di script Web Server Gateway Interface (WSGI), come descritto in Utilizzo di WSGI.

Oltre a soddisfare questi prerequisiti generali, devi utilizzare versioni specifiche di alcune funzionalità di App Engine e librerie di terze parti. Assicurati di aggiornare le versioni che includi e importi nella tua applicazione e di testare a fondo l'applicazione dopo l'upgrade. Il seguente elenco identifica i principali problemi di compatibilità e indica ulteriori risorse per risolverli:

  • Rendimento: il rendimento dell'applicazione potrebbe cambiare dopo l'upgrade a Python 2.7. Se riscontri un aumento della latenza di risposta, puoi aumentare la classe di istanza frontend e attivare le richieste simultanee. Le richieste simultanee consentono alla tua applicazione di funzionare più velocemente con un costo dell'istanza inferiore su istanze più grandi. Per saperne di più, vedi Gestione delle richieste nelle istanze.
  • Django: Devi utilizzare Django 1.2 o versioni successive con Python 2.7. Per informazioni sull'upgrade, consulta le note di rilascio di Django.
  • PyCrypto: Crypto.Util.randpool è stato ritirato a favore di Crypto.Random. Per saperne di più, vedi Cosa fare con RandomPool.
  • webapp: i modelli di app web sono ritirati in Python 2.7. Puoi invece utilizzare direttamente i modelli Django, jinja2 o un motore di modelli diverso a tua scelta.
  • WebOb: Python 2.7 supporta WebOb versione 1.1. Questa versione non è completamente compatibile con la versione precedente (0.9). Se l'applicazione utilizza WebOb, devi testarla a fondo per rilevare eventuali errori derivanti dall'upgrade.
  • zipimport: Python 2.7 non supporta zipimport, ma può importare in modo nativo dai file .zip.
  • simplejson: Python 2.7 non supporta simplejson, ma include l'equivalente, e molto più veloce, modulo json della libreria standard.

Richieste simultanee e WSGI

La funzionalità di Python 2.7 che influisce maggiormente sulla progettazione e sulle prestazioni della tua applicazione è il supporto delle applicazioni multithread in grado di gestire richieste simultanee. La capacità di gestire le richieste simultanee si traduce in un utilizzo migliore che può migliorare significativamente le prestazioni dell'applicazione, soprattutto per le applicazioni che utilizzano classi di istanze superiori che sfruttano più core della CPU.

Per abilitare il multithreading, le applicazioni devono passare dall'approccio basato su Common Gateway Interface (CGI) dei runtime Python precedenti a un approccio basato su Web Server Gateway Interface (WSGI). Questo perché gli script CGI, progettati per gestire le richieste in serie, si basano su variabili di ambiente per l'accesso ai flussi di input e output.

Sebbene il modello WSGI per la gestione delle richieste offra alle applicazioni un accesso più diretto ai flussi di input e output (consentendo richieste simultanee), la gestione di più richieste in parallelo può causare race condition quando la logica di un gestore di richieste si basa su dati con un ambito più ampio di quello locale, ad esempio lo stato dell'applicazione, o interagisce con questi dati. Per questo motivo, è importante programmare in modo difensivo per gestire le condizioni di competizione e garantire che la nuova applicazione WSGI sia thread-safe.

Per maggiori dettagli, consulta Rendere thread-safe l'applicazione.

Aggiornamento di app.yaml

Python 2.7 richiede uno speciale elemento di configurazione runtime nell'intestazione di app.yaml. Tieni presente che l'elemento threadsafe: [ true | false ] è obbligatorio per le applicazioni Python 2.7. Se true, App Engine invia le richieste contemporaneamente; se false, le invia in sequenza. La seguente intestazione app.yaml consente le richieste simultanee:

application: myapp
version: 1
runtime: python27
api_version: 1
threadsafe: true
...

Utilizzo di WSGI

Il runtime Python 2.7 ti consente facoltativamente di eseguire direttamente un'applicazione Web Server Gateway Interface (WSGI), anziché utilizzare l'adattatore run_wsgi_app per eseguire il programma come script CGI. Per farlo, sostituisci il gestore CGI (ad es. myapp.py) in app.yaml con un nome di applicazione WSGI (ad es. myapp.app).

...
handlers:
- url: /.*
  script: myapp.app
...

Devi anche spostare l'oggetto applicazione WSGI nell'ambito globale:

import webapp2

class MainPage(webapp2.RequestHandler):
  def get(self):
    self.response.headers['Content-Type'] = 'text/plain'
    self.response.out.write('Hello, WebApp World!')

app = webapp2.WSGIApplication([('/', MainPage)])

""" Old code:
def main():
  run_wsgi_app(app)

if __name__ == '__main__':
  main()
"""

Puoi comunque specificare i gestori di script CGI in app.yaml; tuttavia, le richieste gestite dagli script CGI vengono elaborate in serie, non contemporaneamente. Inoltre, non puoi avere un app.yaml file che combina script CGI e applicazioni WSGI e non puoi impostare threadsafe su true se definisci gestori CGI.

Alcune convenzioni dei runtime Python precedenti, come l'utilizzo di main() e il controllo di __name__ == 'main', sono ora obsolete. Queste misure hanno contribuito a mantenere memorizzati nella cache gli script CGI del passato, ma ora che esegui direttamente le applicazioni WSGI, questi passaggi non sono più necessari.

Utilizzo della directory root dell'app

In Python 2.5, gli script CGI venivano eseguiti con la directory di lavoro attuale impostata sulla directory che conteneva lo script. Questo è cambiato in Python 2.7. Con WSGI, la directory di lavoro corrente all'inizio del ciclo di vita del gestore delle richieste è la directory principale dell'applicazione.

Esamina il codice dell'applicazione e assicurati che tutti i gestori siano scritti in modo che la directory di lavoro corrente sia la radice dell'applicazione.

Configurazione delle librerie

Il runtime Python 2.7 include alcuni moduli di terze parti. Alcuni sono disponibili per impostazione predefinita, altri solo se configurati. Puoi specificare la versione che vuoi utilizzare.

libraries:
- name: PIL
  version: "1.1.7"
- name: webob
  version: "1.1.1"

Puoi specificare che l'applicazione deve utilizzare l'ultima versione del modulo. Ciò è utile se stai sviluppando un'applicazione che non ha ancora utenti: non devi monitorare le nuove versioni. Tuttavia, se la tua applicazione viene utilizzata attivamente, fai attenzione: potresti sorprenderti che la tua applicazione inizi a utilizzare una nuova versione della libreria non compatibile con le versioni precedenti. Per utilizzare l'ultima versione:

libraries:
- name: PIL
  version: latest

Per un elenco delle librerie supportate, consulta Librerie di terze parti.

Rendere thread-safe l'applicazione

La gestione delle richieste simultanee è semplice se ogni gestore interagisce solo con le variabili all'interno del proprio ambito. Tuttavia, la situazione si complica rapidamente se un gestore modifica le risorse mentre un altro le legge. Assicurarsi che l'applicazione si comporti come previsto, anche se più richieste potrebbero manipolare gli stessi dati e interferire tra loro, è noto come rendere l'applicazione "thread-safe".

La regola principale per la progettazione di un'applicazione thread-safe è limitare l'uso di risorse condivise (come informazioni sullo stato o variabili globali) il più spesso possibile. Tuttavia, di solito non è possibile escluderne completamente l'utilizzo ed è qui che entrano in gioco meccanismi di sincronizzazione come gli oggetti di blocco.

In Python 2.7, hai accesso alla libreria threading di Python, che ti consente di dichiarare un blocco di logica che impone l'esecuzione seriale del codice all'interno anziché concorrente. Considera il seguente codice:

class Configuration(ndb.Model):
  some_config_data = ndb.StringProperty()
  _config_cache = None
  _config_lock = threading.Lock()
  @classmethod
  def get_config(cls):
    with cls._config_lock:
      if not cls._config_cache:
        cls._config_cache = cls.get_by_id('config')
    return cls._config_cache

Questo codice mostra la creazione di una cache di alcune variabili di configurazione globali in una variabile denominata _config_cache. In questo caso, l'utilizzo di un oggetto di blocco denominato _config_lock garantisce che il controllo di un _config_cache preesistente si comporti in modo affidabile. In caso contrario, questa variabile potrebbe farti perdere tempo effettuando più viaggi al Datastore per impostare la stessa variabile più volte con gli stessi dati, perché le richieste in competizione hanno tutte rilevato che _config_cache era vuoto.

Non scegliere alla leggera di utilizzare le serrature. Un blocco forza il blocco di tutti gli altri thread che eseguono questo metodo. Questo può rappresentare un collo di bottiglia per le prestazioni.

Aggiornamento dell'applicazione a webapp2

Nota: se non utilizzi webapp come gestore delle richieste, puoi saltare questa sezione.

Il framework web incluso nel runtime Python 2.7 è stato aggiornato da webapp a webapp2. Tra le altre cose, webapp2 aggiunge un routing URI e una gestione delle eccezioni migliorati, un oggetto di risposta completo e un meccanismo di distribuzione più flessibile.

I modelli webapp sono ora deprecati. Al loro posto, puoi utilizzare Jinja2, Django o un sistema di modelli a tua scelta (purché sia scritto in Python puro).

In App Engine, webapp2 è stato impostato come alias di webapp e webapp2 è compatibile con le versioni precedenti. Tuttavia, dopo l'upgrade, devi comunque testare a fondo l'applicazione e familiarizzare con la nuova sintassi e le nuove funzionalità di webapp2, anziché continuare a fare affidamento sulla compatibilità con le versioni precedenti.

L'upgrade è stato completato.

Una volta caricata l'applicazione, devi testarla a fondo per garantire la compatibilità con le versioni precedenti. Se riscontri problemi, consulta i forum.