문제

특히 Python에서 변수는 스레드 간에 어떻게 공유됩니까?

제가 사용해봤음에도 threading.Thread 변수가 어떻게 공유되는지에 대한 예를 실제로 이해하거나 본 적이 없습니다.메인 스레드와 하위 스레드 간에 공유됩니까, 아니면 하위 스레드 간에만 공유됩니까?이러한 공유를 피하기 위해 언제 스레드 로컬 저장소를 사용해야 합니까?

잠금을 사용하여 스레드 간에 공유 데이터에 대한 액세스를 동기화하는 것에 대한 많은 경고를 보았지만 아직 문제의 좋은 예를 보지 못했습니다.

미리 감사드립니다!

도움이 되었습니까?

해결책

Python에서는 함수 로컬 변수를 제외한 모든 것이 공유됩니다(각 함수 호출은 자체 로컬 집합을 가져오고 스레드는 항상 별도의 함수 호출이기 때문입니다.) 그리고 심지어 변수 자체(객체를 참조하는 이름)만 공유됩니다. 해당 기능에 국한되어 있습니다.객체 자체는 항상 전역적이며 무엇이든 객체를 참조할 수 있습니다.그만큼 Thread 특정 스레드에 대한 개체는 이와 관련하여 특별한 개체가 아닙니다.저장하면 Thread 모든 스레드가 액세스할 수 있는 위치(전역 변수 등)에 있는 개체를 사용하면 모든 스레드가 해당 개체에 액세스할 수 있습니다. Thread 물체.원자적으로 수정하려는 경우 아무것 동일한 스레드에서 생성한 것이 아니고 다른 스레드가 접근할 수 있는 어디에도 저장하지 않은 경우 잠금으로 보호해야 합니다.그리고 모든 스레드는 물론 이 동일한 잠금을 공유해야 합니다. 그렇지 않으면 그다지 효과적이지 않습니다.

실제 스레드 로컬 저장소를 원한다면 그곳이 바로 threading.local 들어 온다.속성 threading.local 스레드 간에 공유되지 않습니다.각 스레드는 자신이 거기에 배치한 속성만 볼 수 있습니다.구현이 궁금하다면 소스는 다음과 같습니다. _threading_local.py 표준 라이브러리에 있습니다.

다른 팁

다음 코드를 고려해보세요.

#/usr/bin/env python

from time import sleep
from random import random
from threading import Thread, local

data = local()

def bar():
    print("I'm called from", data.v)

def foo():
    bar()

class T(Thread):
    def run(self):
        sleep(random())
        data.v = self.getName()   # Thread-1 and Thread-2 accordingly
        sleep(1)
        foo()
 >> T().start(); T().start()
I'm called from Thread-2
I'm called from Thread-1 

여기서 threading.local()은 foo()의 인터페이스를 변경하지 않고 run()에서 bar()로 일부 데이터를 전달하는 빠르고 더러운 방법으로 사용됩니다.

전역 변수를 사용해도 효과가 없다는 점에 유의하세요.

#/usr/bin/env python

from time import sleep
from random import random
from threading import Thread

def bar():
    global v
    print("I'm called from", v)

def foo():
    bar()

class T(Thread):
    def run(self):
        global v
        sleep(random())
        v = self.getName()   # Thread-1 and Thread-2 accordingly
        sleep(1)
        foo()
 >> T().start(); T().start()
I'm called from Thread-2
I'm called from Thread-2 

한편, 이 데이터를 foo()의 인수로 전달할 여유가 있다면 더 우아하고 잘 설계된 방법이 될 것입니다.

from threading import Thread

def bar(v):
    print("I'm called from", v)

def foo(v):
    bar(v)

class T(Thread):
    def run(self):
        foo(self.getName())

그러나 타사 코드나 잘못 설계된 코드를 사용하는 경우 이것이 항상 가능한 것은 아닙니다.

다음을 사용하여 스레드 로컬 저장소를 만들 수 있습니다. threading.local().

>>> tls = threading.local()
>>> tls.x = 4 
>>> tls.x
4

TLS에 저장된 데이터는 각 스레드마다 고유하므로 의도하지 않은 공유가 발생하지 않도록 하는 데 도움이 됩니다.

다른 모든 언어와 마찬가지로 Python의 모든 스레드는 동일한 변수에 액세스할 수 있습니다.'메인 스레드'와 하위 스레드 사이에는 차이가 없습니다.

Python과의 한 가지 차이점은 전역 인터프리터 잠금(Global Interpreter Lock)은 한 번에 하나의 스레드만 Python 코드를 실행할 수 있음을 의미한다는 것입니다.그러나 모든 일반적인 선점 문제가 여전히 적용되고 다른 언어에서와 마찬가지로 스레딩 기본 형식을 사용해야 하기 때문에 액세스 동기화에 있어서는 큰 도움이 되지 않습니다.그러나 이는 성능을 위해 스레드를 사용하고 있었다면 재고해야 함을 의미합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top