112 votes

fonction d'arrière-plan en Python

J'ai un script Python qui affiche parfois des images à l'utilisateur. Ces images peuvent parfois être très grandes et sont souvent réutilisées. Leur affichage n'est pas critique, mais l'affichage du message qui leur est associé l'est. J'ai une fonction qui télécharge l'image nécessaire et l'enregistre localement. Pour l'instant, elle est exécutée en ligne avec le code qui affiche un message à l'utilisateur, mais cela peut parfois prendre plus de 10 secondes pour des images non locales. Existe-t-il un moyen d'appeler cette fonction lorsqu'elle est nécessaire, mais de l'exécuter en arrière-plan pendant que le code continue à s'exécuter ? J'utiliserais simplement une image par défaut jusqu'à ce que la bonne image soit disponible.

172voto

TorelTwiddler Points 2042

Faites quelque chose comme ça :

def function_that_downloads(my_args):
    # do some long download here

puis en ligne, faites quelque chose comme ceci :

import threading
def my_inline_function(some_args):
    # do some stuff
    download_thread = threading.Thread(target=function_that_downloads, name="Downloader", args=some_args)
    download_thread.start()
    # continue doing stuff

Il est possible de vérifier si le fil de discussion est terminé avant de passer à autre chose en appelant download_thread.isAlive()

7voto

Mahmoud Abdelkader Points 5622

Pour ce faire, on utilise généralement un pool de threads et des téléchargements de file d'attente qui émettent un signal, c'est-à-dire un événement, lorsque le traitement de la tâche est terminé. Vous pouvez faire cela dans le cadre de la fonction module de filetage Python fournit.

Pour effectuer ces actions, j'utiliserais objets événementiels et le Module de file d'attente .

Cependant, une démonstration rapide et pratique de ce que vous pouvez faire en utilisant un simple threading.Thread est présentée ci-dessous :

import os
import threading
import time
import urllib2

class ImageDownloader(threading.Thread):

    def __init__(self, function_that_downloads):
        threading.Thread.__init__(self)
        self.runnable = function_that_downloads
        self.daemon = True

    def run(self):
        self.runnable()

def downloads():
    with open('somefile.html', 'w+') as f:
        try:
            f.write(urllib2.urlopen('http://google.com').read())
        except urllib2.HTTPError:
            f.write('sorry no dice')

print 'hi there user'
print 'how are you today?'
thread = ImageDownloader(downloads)
thread.start()
while not os.path.exists('somefile.html'):
    print 'i am executing but the thread has started to download'
    time.sleep(1)

print 'look ma, thread is not alive: ', thread.is_alive()

Il serait probablement judicieux de ne pas faire de sondage comme je le fais ci-dessus. Dans ce cas, je modifierais le code comme suit :

import os
import threading
import time
import urllib2

class ImageDownloader(threading.Thread):

    def __init__(self, function_that_downloads):
        threading.Thread.__init__(self)
        self.runnable = function_that_downloads

    def run(self):
        self.runnable()

def downloads():
    with open('somefile.html', 'w+') as f:
        try:
            f.write(urllib2.urlopen('http://google.com').read())
        except urllib2.HTTPError:
            f.write('sorry no dice')

print 'hi there user'
print 'how are you today?'
thread = ImageDownloader(downloads)
thread.start()
# show message
thread.join()
# display image

Notez qu'il n'y a pas de drapeau daemon ici.

6voto

shaunc Points 545

Je préfère utiliser événement pour ce genre de choses :

import gevent
from gevent import monkey; monkey.patch_all()

greenlet = gevent.spawn( function_to_download_image )
display_message()
# ... perhaps interaction with the user here

# this will wait for the operation to complete (optional)
greenlet.join()
# alternatively if the image display is no longer important, this will abort it:
#greenlet.kill()

Tout fonctionne dans un seul thread, mais chaque fois qu'une opération du noyau se bloque, gevent change de contexte lorsqu'il y a d'autres "greenlets" en cours d'exécution. Les problèmes de verrouillage, etc. sont beaucoup moins importants, puisqu'il n'y a qu'une seule chose en cours d'exécution à la fois, mais l'image continuera à être téléchargée chaque fois qu'une opération bloquante s'exécutera dans le contexte "principal".

En fonction de la quantité et du type de choses que vous voulez faire en arrière-plan, cette solution peut être meilleure ou pire que les solutions basées sur le threading ; elle est certainement beaucoup plus évolutive (c'est-à-dire que vous pouvez faire beaucoup plus de choses en arrière-plan), mais ce n'est peut-être pas une préoccupation dans la situation actuelle.

0voto

rehman azhar Points 11
import threading
import os

def killme():
    if keyboard.read_key() == "q":
        print("Bye ..........")
        os._exit(0)

threading.Thread(target=killme, name="killer").start()

Si vous souhaitez ajouter d'autres clés, ajoutez def et threading.Thread(target=killme, name="killer").start() plusieurs fois. Cela n'est pas très esthétique mais fonctionne beaucoup mieux que des codes complexes.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X