> For the complete documentation index, see [llms.txt](https://kerasnoone.gitbook.io/garnet/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://kerasnoone.gitbook.io/garnet/gong-cheng-zhan/python/bing-fa/duo-xian-cheng/0x03-xian-cheng-zhuan-you-zhuang-tai.md).

# 0x03 线程专有状态

## 问题

有些情况下, 我们需要保存当前运行线程的**专有状态**, 而且这个状态对其他线程是**不可见的**, 即其他线程不会对这个状态产生影响, 做出修改. 在这多线程程序中是很常见的需求.

可以通过**threading.local()**&#x521B;建一个**线程本地存储对象**, 将需要保存的变量, 以这个对象**属性**的形式进行保存和读取. 只对当前运行的线程可见, 其他线程无法感知.

## 使用方法

以`socket`编程为例, 每个线程管理一个独立的socket, 以避免相互之间的干扰.

```python
import threading
from functools import partial
from socket import socket, AF_INET, SOCK_STREAM

class LazyConnection:
    def __init__(self, address, family=AF_INET, types=SOCK_STREAM):
        self.address = address
        self.family = family
        self.type = types
        self.local = threading.local()
        print("type of local:", type(self.local))

    def __enter__(self):
        if hasattr(self.local, "sock"):
            raise RuntimeError("already connected")
        self.local.sock = socket(self.family, self.type)
        self.local.sock.connect(self.address)
        return self.local.sock

    def __exit__(self, exc_ty, exc_val, tb):
        self.local.sock.close()
        del self.local.sock

def test(conn):
    with conn as s:
        s.send(b"GET /index.html HTTP/1.0\r\n")
        s.send(b"Host: www.python.org\r\n")
        s.send(b"\r\n")
        res = b"".join(iter(partial(s.recv, 8192), b""))
    print("Got {} bytes".format(len(res)))

conn = LazyConnection(("www.python.org", 80))
t1 = threading.Thread(target=test, args=(conn,))
t2 = threading.Thread(target=test, args=(conn,))
t1.start()
t2.start()
t1.join()
t2.join()
```

输出为:

```
type of local: <class '_thread._local'>
Got 392 bytes
Got 392 bytes
```

所有线程都公用一个`LazyConnection`的实例. 实例对象的`local`属性供每个线程单独使用, 每个线程将自己所操作的独立的`socket`保存为`local`对象的`sock`属性. 这样`LazyConnection`就能安全地用于多线程环境中了.

每个线程实际上都创建了自己专属的`socket`连接, 以`self.local.sock`的形式保存. 当不同的线程在`socket`上执行操作时, 它们并不会互相产生影响, 因为它们都是在不同的`socket`上完成操作的.
