2016-08-02 3 views
3

Оба кода, похоже, имеют аналогичную производительность. Как работает область действия в этом случае? Кто-нибудь из них лучше другого? Есть ли лучший способ добиться такого же поведения?Область применения Python

код 1:

class ex: 
    b = 6 
    def foo(self, a): 
    def fooHandler(a): 
     while True: 
     print a 
     time.sleep(1) 
    threading.Thread(target=fooHandler, args=(a,)).start() 
x = ex() 
x.foo(10) 
x.foo(100) 
x.foo(1000) 

код 2:

class ex: 
    b = 6 
    def foo(self, a): 
    def fooHandler(): 
     while True: 
     print a 
     time.sleep(1) 
    threading.Thread(target=fooHandler).start() 
x = ex() 
x.foo(10) 
x.foo(100) 
x.foo(1000) 
+0

Отступ был испорчен, когда я скопировал его из моего редактора, он должен работать сейчас – user3019917

+0

Возможно, вы захотите прочитать следующее: http://stackoverflow.com/questions/4020419/why-arent-python-nested-functions- call-closures – dmitri

+0

@dmitri ссылка была полезна :) спасибо – user3019917

ответ

1

Ну, это разница в сгенерированном коде (по крайней мере при использовании CPython 2.7.12):

def runThread(a): 
    def threadFunc(): 
     while True: 
      print a 
      time.sleep(1) 

    t = threading.Thread(target=threadFunc) 
    t.start() 

выдаст LOAD_GLOBAL опкода для a внутри threadFunc() (выход из inspect.dis.dis()):

8   9 LOAD_GLOBAL    1 (a) 

в то время как

def runThread(a): 
    def threadFunc(a): 
     while True: 
      time.sleep(1) 

    t = threading.Thread(target=threadFunc, args=(a,)) 
    t.start() 

выпустит LOAD_FAST опкод:

8   9 LOAD_FAST    0 (a) 

LOAD_FAST происходит, потому что компилятор знает, что a является параметром и, таким образом, поиск должен только произойти WRT. к текущему пространству имен. LOAD_FAST (отсюда и название) потенциально быстрее, чем LOAD_GLOBAL, но если вам нужно подумать о различиях в показателях производительности, вы, вероятно, не должны использовать Python в первую очередь.

И да, все кричит «подробности реализации» для меня тоже.

Объем импорта a из внешнего объема дает вам дополнительную гибкость, поскольку вы все еще можете изменить a даже после того, как поток уже запущен. При передаче a в качестве параметра функции потока эта возможность более или менее исчезает. В любом случае, я бы рассмотрел первый антипаттерн, если его a является флагом завершения потока.

0

Это не имеет ничего общего с многопоточности, это просто вопрос, используя значения из вложенного объема по сравнению с передачей его в явном виде как аргумент и использование его из локальной области.

Не имеет особого значения, какой подход вы используете в этом случае; вы используете одно и то же значение в любом случае. Поиск его во вложенной области является более дорогостоящим, но только тривиально (он по существу эквивалентен одиночному поиску dict, где локальные поисковые запросы ближе к производительности доступа к массиву).

Если вам необходимо изменить привязку a во время выполнения этой функции, вы не сможете сделать это с неявным вложением доступа к областям (вам придется использовать другое имя), потому что вы не можете читать и писать из вложенного переменная области видимости в Python 2 (в которой отсутствует ключевое слово nonlocal). Использование другого имени (изначально установленного на a) было бы похоже на принятие его в качестве аргумента в любом случае, так что опять же, никакого существенного различия.

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