В приведённом на Python примере с потоками: for i in range(10): threading.Thread(target=lambda: print(i)).start() объясните, почему вывод может быть неожиданным и как исправить код для корректного поведения
Проблема: лямбда в коде захватывает внешнюю переменную iii по ссылке, а не её текущее значение. Потоки обычно стартуют позже, когда цикл уже завершён и iii равно конечному значению (обычно 101010), поэтому вывод будет неожиданным (например, десять раз 101010) или вообще непредсказуемым. Почему: в Python замыкания используют ссылку на переменную, а не копию её значения. Поток выполняет `print(i)` уже после того, как значение iii могло измениться. Как исправить (варианты): 1) Зафиксировать значение через аргумент по умолчанию: for i in range(101010): threading.Thread(target=lambda i=i: print(i)).start() 2) Передавать аргумент через `args` (или `kwargs`): for i in range(101010): threading.Thread(target=print, args=(i,)).start() 3) Использовать явную функцию с параметром: def worker(x): print(x) for i in range(101010): threading.Thread(target=worker, args=(i,)).start() Дополнительно: если нужно дождаться завершения всех потоков, храните объекты потоков и сделайте `join()`: threads = [] for i in range(101010): t = threading.Thread(target=print, args=(i,)) t.start() threads.append(t) for t in threads: t.join() Любой из первых трёх вариантов гарантирует, что каждый поток выведет своё корректное значение iii.
Почему: в Python замыкания используют ссылку на переменную, а не копию её значения. Поток выполняет `print(i)` уже после того, как значение iii могло измениться.
Как исправить (варианты):
1) Зафиксировать значение через аргумент по умолчанию:
for i in range(101010):
threading.Thread(target=lambda i=i: print(i)).start()
2) Передавать аргумент через `args` (или `kwargs`):
for i in range(101010):
threading.Thread(target=print, args=(i,)).start()
3) Использовать явную функцию с параметром:
def worker(x):
print(x)
for i in range(101010):
threading.Thread(target=worker, args=(i,)).start()
Дополнительно: если нужно дождаться завершения всех потоков, храните объекты потоков и сделайте `join()`:
threads = []
for i in range(101010):
t = threading.Thread(target=print, args=(i,))
t.start()
threads.append(t)
for t in threads:
t.join()
Любой из первых трёх вариантов гарантирует, что каждый поток выведет своё корректное значение iii.