Points faciles à commettre lors de l'utilisation de lambda pendant le traitement de la boucle Python

J'ai écrit le code suivant pour "télécharger 500 fichiers en parallèle" en Python.

from time import sleep
from concurrent.futures import ThreadPoolExecutor

def func(i):
    #En fait, processus de téléchargement de fichiers
    sleep(1)
    print(f"{i}\n", flush=True, end="")

with ThreadPoolExecutor(max_workers=3) as executor:
    for i in range(500):
        # 0~Télécharger le fichier 499 en parallèle
        executor.submit(
            lambda: func(i)
        )

Lorsque j'ai exécuté cela, le comportement était le suivant: "Le traitement est exécuté plusieurs fois avec le même numéro".

499
499
499
499
499
499
144
145
146
1
0
2
(Omis ci-dessous)

Apparemment, "la valeur de ʻi est lue lorsque func est réellement exécutée, tant de valeurs de ʻi à la fin de la boucle sont lues".

En utilisant functools.partial comme indiqué ci-dessous, il sera exécuté comme prévu à l'origine pour" exécuter le processus avec toutes les valeurs ʻi` de 0 à 499 ".

from time import sleep
from functools import partial
from concurrent.futures import ThreadPoolExecutor

def func(i):
    sleep(1)
    print(f"{i}\n", flush=True, end="")

with ThreadPoolExecutor(max_workers=3) as executor:
    for i in range(500):
        executor.submit(
            partial(func, i)
        )

La sortie ressemble à ceci.

0
2
1
3
5
4
6
7
8
9
10
11
12
13
14
(Omis ci-dessous)

De plus, comme je l'ai appris de ce blog, l'argument par défaut de Python Il semble y avoir un moyen de se lier avec. Je pense qu'il est plus facile de transmettre l'intention du programme en utilisant «partial», mais c'est certainement intéressant.

from time import sleep
from concurrent.futures import ThreadPoolExecutor

def func(i):
    sleep(1)
    print(f"{i}\n", flush=True, end="")

with ThreadPoolExecutor(max_workers=3) as executor:
    for i in range(500):
        executor.submit(
            lambda x=i: func(x)
        )

Postscript

D'un ami, " submit reçoit l'argument de la fonction à exécuter Mais alors J'ai reçu un tsukkomi disant: "Est-ce inutile?", Mais je pense que c'est exactement le cas. Voici le code pour une utilisation réelle.

with ThreadPoolExecutor(max_workers=3) as executor:
    for i in range(500):
        executor.submit(func, i)

Recommended Posts

Points faciles à commettre lors de l'utilisation de lambda pendant le traitement de la boucle Python
Notation d'inclusion de liste Python facile à oublier
Cinq types de données Python utiles faciles à oublier
Traitement d'exécution périodique lors de l'utilisation de tkinter [Python3]
10 erreurs Python communes aux débutants
Comment prendre plusieurs arguments lors d'un traitement parallèle à l'aide du multitraitement en python
Qu'utilisez-vous lorsque vous testez avec Python?
[LPIC 101] J'ai essayé de résumer les options de commande qui sont faciles à faire une erreur
Une petite histoire à savoir comme un point addictif lors de l'écriture d'applications Twilio à l'aide de Python sur AWS Lambda
Erreur due à un conflit entre pythons lors de l'utilisation de gurobi
Un moyen facile de gratter avec Python en utilisant Google Colab
Vérifiez types_map lors de l'utilisation de mimetypes avec AWS Lambda (Python)
Comment créer un package Python à l'aide de VS Code
[Introduction à Python] Comment arrêter la boucle en utilisant break?
Points à garder à l'esprit lors du traitement des chaînes en Python2
Ce à quoi j'étais accro lors de l'utilisation de Python tornado
Points à garder à l'esprit lors du traitement des chaînes en Python 3
Les messages d'erreur Python sont spécifiques et faciles à comprendre "ga" (avant cela, deux points (:) et point-virgule (;))
Une histoire qui facilite l'estimation de la surface habitable à l'aide d'Elasticsearch et de Python