中学社会668760 views
いろは3010814 views
小学社会310485 views
高校化学2924392 views
高校国語788336 views
数学講師2886227 views
高校生物551766 views
ヒストリア290598 views
りんご209490 views
LaTeX962153 views
Help
Tools
NewsSpreadsheetCalendarSlidesTier ListPen ToolIllustrationCrayonPixel ArtASCII ArtPerspectiveEndless StairsGraphMind MapER DiagramFamily TreeMemeCurved TextImage EditorMosaicRetro FilterPencil SketchOCR/HighlighterMakeup EditorFaviconVideo TrimmerScrolling VideoVideo TitleColor PickerColor ExtractorBonfireFireworksWater RippleWater SplashBreaking GlassWood GrainMarble TextureCSS ButtonIcon MakerBar ChartGrouped Bar ChartStacked Bar ChartPie ChartLine ChartArea ChartStacked Area ChartScatter Plot3D Bar Chart3D Pie ChartBar Chart RaceBubble ChartPopulation PyramidPictogramEarningsCandlestick ChartInvestment RiskMortgage SimulatorCalculatorMatrix CalculatorFunction GraphPolynomial ExpansionVenn DiagramField VisualizerRubik's Cube Group TheoryTraveling SalesmanVoronoi and DelaunayFractalColumn ArithmeticDraw Math FiguresArithmetic AnimationArithmetic Word ProblemsCounting with Tree DiagramsCube NetsCross SectionsMotion PathMechanicsWavesLight and LensesThermodynamicsHow Semiconductors WorkMolecular StructuresAtomic OrbitalsElectrochemical CellsChemical EquilibriumCrystal LatticesBuffer pHComplex IonsDNA Double HelixCell DivisionMembrane ChannelsNerve ImpulseRock ClassificationWeatherConstellationsSolar and Lunar Eclipses3D ModelingFloor PlanSeismic StructuresIntersection TurnMaglevCooking AnimationOrigamiLive Viewer CountGeoJSON MapRailway MapPopulation MapCrime MapLand Price MapSchool MapShrine and Castle MapHouse of Representatives MapWord MapSolitaireReversiHakoiri MusumeChessHamburgerRippleSlide Puzzle MakerNeon PinballNovel MakerJapanese Typing PracticePiano Score EditorMusic Theory

English

Python のスレッドローカル変数

threading.local() は、スレッドごとに独立したデータを保持するための仕組みです。グローバル変数のように見えますが、各スレッドには自分専用の値が格納されます。

スレッドローカル変数とは

通常のグローバル変数は、すべてのスレッドで共有されます。しかし threading.local() を使うと、スレッドごとに別々の値を持てます。

import threading

# スレッドローカル変数を作成
local_data = threading.local()

def worker(name):
    local_data.name = name  # このスレッド専用の値
    print(f"設定: {local_data.name}")
    
    # 少し待ってから再度確認
    import time
    time.sleep(0.1)
    print(f"確認: {local_data.name}")  # 他のスレッドの影響を受けない

threads = [
    threading.Thread(target=worker, args=("Alice",)),
    threading.Thread(target=worker, args=("Bob",)),
    threading.Thread(target=worker, args=("Charlie",)),
]

for t in threads:
    t.start()
for t in threads:
    t.join()

各スレッドは自分の name を保持し、他のスレッドからは見えません。

グローバル変数との違い

グローバル変数

すべてのスレッドで共有される。同時アクセスで競合が発生する可能性。

スレッドローカル変数

スレッドごとに独立。他のスレッドからアクセスできない。

import threading
import time

# グローバル変数(共有される)
global_value = None

# スレッドローカル変数(独立)
local_value = threading.local()

def worker(n):
    global global_value
    global_value = n
    local_value.value = n
    
    time.sleep(0.1)
    
    print(f"Thread {n}: global={global_value}, local={local_value.value}")

threads = [threading.Thread(target=worker, args=(i,)) for i in range(3)]
for t in threads:
    t.start()
for t in threads:
    t.join()
# global_value は最後に設定した値で上書きされる
# local_value.value は各スレッドで独立した値を保持

実用例:データベース接続

スレッドごとにデータベース接続を管理する例です。

import threading
import sqlite3

# スレッドごとの接続を管理
connections = threading.local()

def get_connection():
    if not hasattr(connections, 'conn'):
        connections.conn = sqlite3.connect(':memory:')
        print(f"{threading.current_thread().name}: 新しい接続を作成")
    return connections.conn

def worker():
    conn = get_connection()
    cursor = conn.cursor()
    cursor.execute("SELECT 1")
    print(f"{threading.current_thread().name}: クエリ実行完了")

threads = [threading.Thread(target=worker, name=f"Thread-{i}") for i in range(3)]
for t in threads:
    t.start()
for t in threads:
    t.join()

各スレッドが自分専用の接続を持つため、接続の競合を防げます。

実用例:リクエストコンテキスト

Web フレームワークでリクエストごとのコンテキストを管理する例です。

import threading

request_context = threading.local()

def set_user(user_id):
    request_context.user_id = user_id

def get_user():
    return getattr(request_context, 'user_id', None)

def process_request(user_id):
    set_user(user_id)
    print(f"{threading.current_thread().name}: ユーザー {get_user()} の処理中")
    # 処理...

threads = [
    threading.Thread(target=process_request, args=(f"user_{i}",))
    for i in range(3)
]
for t in threads:
    t.start()
for t in threads:
    t.join()

初期値を持つスレッドローカル

サブクラスを作って初期値を設定することもできます。

import threading

class LocalData(threading.local):
    def __init__(self):
        self.value = 0  # 各スレッドでの初期値

local_data = LocalData()

def worker(n):
    print(f"初期値: {local_data.value}")
    local_data.value = n
    print(f"設定後: {local_data.value}")

threads = [threading.Thread(target=worker, args=(i,)) for i in range(3)]
for t in threads:
    t.start()
for t in threads:
    t.join()

注意点

スレッドローカル変数の値は、スレッドが終了すると失われます。

import threading

local = threading.local()

def worker():
    local.data = "スレッドのデータ"
    print(f"設定: {local.data}")

thread = threading.Thread(target=worker)
thread.start()
thread.join()

# メインスレッドからはアクセスできない
try:
    print(local.data)
except AttributeError:
    print("メインスレッドには data がない")

スレッドローカル変数は、スレッドごとに独立した状態を持つ必要がある場面で非常に便利です。