Python의 스레드 로컬 저장소
Python에서 스레드 로컬 저장소를 어떻게 사용합니까?
관련
- Python의 "스레드 로컬 저장소"란 무엇이며 왜 필요합니까? -이 스레드는 변수가 공유 될 때 더 집중된 것으로 보입니다.
- 특정 함수가 Python의 스택에 있는지 여부를 확인하는 효율적인 방법 -Alex Martelli가 좋은 솔루션을 제공합니다.
스레드 로컬 스토리지는 스레드 작업자 풀이 있고 각 스레드가 네트워크 또는 데이터베이스 연결과 같은 자체 리소스에 액세스해야하는 경우에 유용합니다. 점을 유의 threading
모듈 (과정 글로벌 데이터에 액세스 할 수) 스레드의 일반 개념을 사용하지만이 때문에 글로벌 통역 잠금 너무 유용하지 않습니다. 다른 multiprocessing
모듈은 각각에 대해 새로운 하위 프로세스를 생성하므로 모든 전역은 스레드 로컬이됩니다.
스레딩 모듈
다음은 간단한 예입니다.
import threading
from threading import current_thread
threadLocal = threading.local()
def hi():
initialized = getattr(threadLocal, 'initialized', None)
if initialized is None:
print("Nice to meet you", current_thread().name)
threadLocal.initialized = True
else:
print("Welcome back", current_thread().name)
hi(); hi()
다음과 같이 인쇄됩니다.
Nice to meet you MainThread
Welcome back MainThread
쉽게 간과되는 한 가지 중요한 사항 : threading.local()
객체는 스레드 당 한 번이나 함수 호출 당 한 번이 아니라 한 번만 생성하면됩니다. global
또는 class
수준은 이상적인 위치입니다.
그 이유는 다음과 같습니다. threading.local()
실제로 호출 될 때마다 새 인스턴스를 생성하므로 (팩토리 또는 클래스 호출과 마찬가지로) threading.local()
여러 번 호출 하면 원래 객체를 지속적으로 덮어 쓰며, 이는 모두가 원하는 것이 아닙니다. 스레드가 기존 threadLocal
변수 (또는 호출 된 모든 항목)에 액세스하면 해당 변수에 대한 자체 개인보기를 얻습니다.
의도 한대로 작동하지 않습니다.
import threading
from threading import current_thread
def wont_work():
threadLocal = threading.local() #oops, this creates a new dict each time!
initialized = getattr(threadLocal, 'initialized', None)
if initialized is None:
print("First time for", current_thread().name)
threadLocal.initialized = True
else:
print("Welcome back", current_thread().name)
wont_work(); wont_work()
결과는 다음과 같습니다.
First time for MainThread
First time for MainThread
다중 처리 모듈
multiprocessing
모듈이 각 스레드에 대해 새 프로세스를 생성하기 때문에 모든 전역 변수는 스레드 로컬 입니다.
processed
카운터가 스레드 로컬 저장소의 예인 다음 예를 고려하십시오 .
from multiprocessing import Pool
from random import random
from time import sleep
import os
processed=0
def f(x):
sleep(random())
global processed
processed += 1
print("Processed by %s: %s" % (os.getpid(), processed))
return x*x
if __name__ == '__main__':
pool = Pool(processes=4)
print(pool.map(f, range(10)))
다음과 같이 출력됩니다.
Processed by 7636: 1
Processed by 9144: 1
Processed by 5252: 1
Processed by 7636: 2
Processed by 6248: 1
Processed by 5252: 2
Processed by 6248: 2
Processed by 9144: 2
Processed by 7636: 3
Processed by 5252: 3
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
... 물론 스레드 ID와 각각의 수와 순서는 실행마다 다릅니다.
스레드 로컬 저장소는 단순히 네임 스페이스 (속성 표기법을 통해 액세스 된 값 포함)로 생각할 수 있습니다. 차이점은 각 스레드가 자체 속성 / 값 집합을 투명하게 가져 오므로 한 스레드가 다른 스레드의 값을 볼 수 없다는 것입니다.
일반 객체와 마찬가지로 threading.local
코드에서 여러 인스턴스를 만들 수 있습니다 . 지역 변수, 클래스 또는 인스턴스 멤버 또는 전역 변수 일 수 있습니다. 각각은 별도의 네임 스페이스입니다.
다음은 간단한 예입니다.
import threading
class Worker(threading.Thread):
ns = threading.local()
def run(self):
self.ns.val = 0
for i in range(5):
self.ns.val += 1
print("Thread:", self.name, "value:", self.ns.val)
w1 = Worker()
w2 = Worker()
w1.start()
w2.start()
w1.join()
w2.join()
산출:
Thread: Thread-1 value: 1
Thread: Thread-2 value: 1
Thread: Thread-1 value: 2
Thread: Thread-2 value: 2
Thread: Thread-1 value: 3
Thread: Thread-2 value: 3
Thread: Thread-1 value: 4
Thread: Thread-2 value: 4
Thread: Thread-1 value: 5
Thread: Thread-2 value: 5
Note how each thread maintains its own counter, even though the ns
attribute is a class member (and hence shared between the threads).
The same example could have used an instance variable or a local variable, but that wouldn't show much, as there's no sharing then (a dict would work just as well). There are cases where you'd need thread-local storage as instance variables or local variables, but they tend to be relatively rare (and pretty subtle).
As noted in the question, Alex Martelli gives a solution here. This function allows us to use a factory function to generate a default value for each thread.
#Code originally posted by Alex Martelli
#Modified to use standard Python variable name conventions
import threading
threadlocal = threading.local()
def threadlocal_var(varname, factory, *args, **kwargs):
v = getattr(threadlocal, varname, None)
if v is None:
v = factory(*args, **kwargs)
setattr(threadlocal, varname, v)
return v
Can also write
import threading
mydata = threading.local()
mydata.x = 1
mydata.x will only exist in the current thread
My way of doing a thread local storage across modules / files. The following has been tested in Python 3.5 -
import threading
from threading import current_thread
# fileA.py
def functionOne:
thread = Thread(target = fileB.functionTwo)
thread.start()
#fileB.py
def functionTwo():
currentThread = threading.current_thread()
dictionary = currentThread.__dict__
dictionary["localVar1"] = "store here" #Thread local Storage
fileC.function3()
#fileC.py
def function3():
currentThread = threading.current_thread()
dictionary = currentThread.__dict__
print (dictionary["localVar1"]) #Access thread local Storage
In fileA, I start a thread which has a target function in another module/file.
In fileB, I set a local variable I want in that thread.
In fileC, I access the thread local variable of the current thread.
Additionally, just print 'dictionary' variable so that you can see the default values available, like kwargs, args, etc.
참고URL : https://stackoverflow.com/questions/1408171/thread-local-storage-in-python
'program story' 카테고리의 다른 글
다중 클라이언트 응용 프로그램에 대해 단일 또는 다중 데이터베이스 설정을 사용해야합니까? (0) | 2020.11.30 |
---|---|
자동 증가로 열의 시작 값 설정 (0) | 2020.11.30 |
자바 스크립트에서 날짜가 같은지 확인 (0) | 2020.11.30 |
국소 최댓값과 최솟값 찾기 (0) | 2020.11.30 |
내 로컬 Git 저장소를 원격 Git 저장소로 이동하려면 어떻게해야합니까? (0) | 2020.11.30 |