============================ 12.6 ä¿å˜çº¿ç¨‹çš„状æ€ä¿¡æ¯ ============================ ---------- 问题 ---------- ä½ éœ€è¦ä¿å˜æ£åœ¨è¿è¡Œçº¿ç¨‹çš„状æ€ï¼Œè¿™ä¸ªçжæ€å¯¹äºŽå…¶ä»–的线程是ä¸å¯è§çš„。 ---------- 解决方案 ---------- 有时在多线程编程ä¸ï¼Œä½ 需è¦åªä¿å˜å½“å‰è¿è¡Œçº¿ç¨‹çš„状æ€ã€‚ è¦è¿™ä¹ˆåšï¼Œå¯ä½¿ç”¨ ``thread.local()`` 创建一个本地线程å˜å‚¨å¯¹è±¡ã€‚ 对这个对象的属性的ä¿å˜å’Œè¯»å–æ“作都åªä¼šå¯¹æ‰§è¡Œçº¿ç¨‹å¯è§ï¼Œè€Œå…¶ä»–线程并ä¸å¯è§ã€‚ 作为使用本地å˜å‚¨çš„一个有趣的实际例å, 考虑在8.3å°èŠ‚å®šä¹‰è¿‡çš„ ``LazyConnection`` 上下文管ç†å™¨ç±»ã€‚ 䏋颿ˆ‘们对它进行一些å°çš„修改使得它å¯ä»¥é€‚用于多线程: .. code-block:: python from socket import socket, AF_INET, SOCK_STREAM import threading class LazyConnection: def __init__(self, address, family=AF_INET, type=SOCK_STREAM): self.address = address self.family = AF_INET self.type = SOCK_STREAM self.local = threading.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 代ç ä¸ï¼Œè‡ªå·±è§‚察对于 ``self.local`` 属性的使用。 它被åˆå§‹åŒ–为一个 ``threading.local()`` 实例。 其他方法æ“作被å˜å‚¨ä¸º ``self.local.sock`` 的套接å—对象。 有了这些就å¯ä»¥åœ¨å¤šçº¿ç¨‹ä¸å®‰å…¨çš„使用 ``LazyConnection`` 实例了。例如: .. code-block:: python from functools import partial 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') resp = b''.join(iter(partial(s.recv, 8192), b'')) print('Got {} bytes'.format(len(resp))) if __name__ == '__main__': 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() å®ƒä¹‹æ‰€ä»¥è¡Œå¾—é€šçš„åŽŸå› æ˜¯æ¯ä¸ªçº¿ç¨‹ä¼šåˆ›å»ºä¸€ä¸ªè‡ªå·±ä¸“属的套接å—连接(å˜å‚¨ä¸ºself.local.sock)。 å› æ¤ï¼Œå½“ä¸åŒçš„çº¿ç¨‹æ‰§è¡Œå¥—æŽ¥å—æ“作时,由于æ“作的是ä¸åŒçš„套接å—ï¼Œå› æ¤å®ƒä»¬ä¸ä¼šç›¸äº’å½±å“。 ---------- 讨论 ---------- 在大部分程åºä¸åˆ›å»ºå’Œæ“作线程特定状æ€å¹¶ä¸ä¼šæœ‰ä»€ä¹ˆé—®é¢˜ã€‚ ä¸è¿‡ï¼Œå½“å‡ºäº†é—®é¢˜çš„æ—¶å€™ï¼Œé€šå¸¸æ˜¯å› ä¸ºæŸä¸ªå¯¹è±¡è¢«å¤šä¸ªçº¿ç¨‹ä½¿ç”¨åˆ°ï¼Œç”¨æ¥æ“作一些专用的系统资æºï¼Œ æ¯”å¦‚ä¸€ä¸ªå¥—æŽ¥å—æˆ–æ–‡ä»¶ã€‚ä½ ä¸èƒ½è®©æ‰€æœ‰çº¿ç¨‹å…±äº«ä¸€ä¸ªå•独对象, å› ä¸ºå¤šä¸ªçº¿ç¨‹åŒæ—¶è¯»å’Œå†™çš„æ—¶å€™ä¼šäº§ç”Ÿæ··ä¹±ã€‚ 本地线程å˜å‚¨é€šè¿‡è®©è¿™äº›èµ„æºåªèƒ½åœ¨è¢«ä½¿ç”¨çš„线程ä¸å¯è§æ¥è§£å†³è¿™ä¸ªé—®é¢˜ã€‚ 本节ä¸ï¼Œä½¿ç”¨ ``thread.local()`` å¯ä»¥è®© ``LazyConnection`` 类支æŒä¸€ä¸ªçº¿ç¨‹ä¸€ä¸ªè¿žæŽ¥ï¼Œ è€Œä¸æ˜¯å¯¹äºŽæ‰€æœ‰çš„è¿›ç¨‹éƒ½åªæœ‰ä¸€ä¸ªè¿žæŽ¥ã€‚ å…¶åŽŸç†æ˜¯ï¼Œæ¯ä¸ª ``threading.local()`` 实例为æ¯ä¸ªçº¿ç¨‹ç»´æŠ¤ç€ä¸€ä¸ªå•独的实例å—典。 所有普通实例æ“作比如获å–ã€ä¿®æ”¹å’Œåˆ 除值仅仅æ“作这个å—典。 æ¯ä¸ªçº¿ç¨‹ä½¿ç”¨ä¸€ä¸ªç‹¬ç«‹çš„å—典就å¯ä»¥ä¿è¯æ•°æ®çš„隔离了。