2016-07-30 1 views
0

Я относительно новичок в Python, но немного разбираюсь в кодировании. Этот маленький кусочек кода сводит меня с ума. Почему на самом деле метод summe() так упрям ​​в нитке? Потоки, кажется, обрабатываются последовательно. Это означает, что каждый следующий поток запускается только в том случае, если предыдущий закончен. Я не знаю почему? Все четыре нити должны начинаться «параллельно» и работать «параллельно». Даже если они работают только на одном ядре из-за ограничений GIL.Computationally-heavy Thread «висит» в Python 3 - Почему?

Та же процедура с методом подсчета () работы «» параллельно, как предполагалось.

Дорогой интернет, пожалуйста, помогите мне ...

Павла :)

#!/usr/bin/python3 

import threading 

# Hanging... 
def summe(n): 
    print("Start") 
    s = sum(range(n)) 
    print("Done") 

# Works like a charm 
def count(n): 
    print("Start") 
    while n > 0: 
     n = n-1 
    print("Done") 

# This works 
for i in range(3): 
    threading.Thread(target=count,args=(10000000000000,)).start() 

# This hangs... 
for i in range(3): 
    threading.Thread(target=summe,args=(10000000000000,)).start() 

ответ

1

Благодаря GIL, встроенный в функции, как sum атомарный!; как только он начнется, он не будет прерван, пока он не завершится. В то время как возможно, что система потоковой обработки может выбрать только первую строку summe перед переключением контекста, чтобы начать следующий поток, это маловероятно. Вы видите «зависание»: sum в первой блокировке потока, пока он, наконец, не завершится.

В то же время, в count не существует ни одной длинной атомной операции, которая блокируется на GIL; просто много (и много-много и ...) небольших операций, что позволяет много возможностей запускать каждый поток и возвращаться к основному потоку. Используя намного меньшее значение для n, вы можете увидеть каждый запуск count, затем через несколько минут они будут завершены. Аналогично, вы можете наблюдать за тремя потоками summe, которые выполняются почти поочередно (в одном тесте, который я запускал, первый выполнялся до завершения, прежде чем запускать два других параллельно).

+0

Большое спасибо за очень быстрый ответ. Моя проблема заключается в том, что реальный метод (sum() был всего лишь примером). Я использую написанный в Cython, очень большой и, очевидно, атомный. Есть ли способ заставить такой метод быть не атомарным? – Paulquappe

+0

@Paulquappe Похоже, вам может быть лучше распараллелить вашу функцию Cython. Если вы можете избавиться от своих вызовов API Python, вы можете освободить GIL и реализовать надлежащий параллелизм с помощью OpenMP. –

+0

Многие, большое спасибо. Я думаю, это звучит как план. – Paulquappe

Смежные вопросы