listbox在线程中使用_Threading.local()使用与原理剖析

本文探讨了Python中的Threading.local()的用途和原理,它提供了一个方便、快速获取线程专属数据的方式。通过实例,解释了如何使用Threading.local()创建线程私有的数据存储,并对比了自定义实现的复杂性,强调其在多线程场景下数据管理的便利性。
摘要由CSDN通过智能技术生成

前言

为什么要写这个方法呢?因为它确实太重要了,包括后期的 Flask 框架源码中都有它的影子。

那么我们就来瞄一眼这个东西是啥吧。

作用

在Python官方中文文档中(Python3.8.4),对它的介绍其实并不是很详细

c3338ce1f32fd4408fc40a736d779d7e.png

其实它的功能非常简单,如下:

在一个全局的容器中可以存放一些线程独有的数据,这些数据应是某一线程私有的,是除了本线程外的其他线程访问不到的。

举个例子,例如你用迅雷下载的时候每条线程的下载进度不一样,我们需要将下载进度这个数据存储起来,怎么存储?自己创建一个具有线程安全性的列表或字典?那太麻烦了, 请记住一点,数据怎么存不重要,关键是要方便取,取的快,取的准才是王道 ,所以直接用 thrading.local() 方法即可。

我来画一张吧,灵魂画师上线,能用图描述绝对不打字。

e97472e72a734db88a311a3474d73501.png

基本使用

threading.local() :可以实例化出一个寄存柜,这个寄存柜是全局化的

寄存柜对象.你想放的东西名字 = 东西 :你可以在线程中这样放入一个独有的物件

寄存柜对象.你放过的东西的名字 :这样,你就可以将你存放进的东西拿出来。注意,只有你才能拿出来,其他人拿不了。

import threadingimport timedef operate(name):    """操作"""    print("三个月后,{0}忽然想起了自己有件东西放在柜子里,决定取出来".format(name))    print("最后他从自己的柜子里取出来了:",Locker.article)def people(article):    name = threading.current_thread().getName()  # 获取线程名    Locker.article = article  #  这就表示将私有的的一件物品放在了寄存柜里    print("{0}将{1}放在了寄存柜里...".format(name,article))    time.sleep(3)  # 过了三个月,这期间发生了很多事    operate(name)if __name__ == '__main__':    Locker = threading.local()  # 好了寄存柜放在全局了    t1 = threading.Thread(target=people,args=("一封情书",),name="小王")    t2 = threading.Thread(target=people,args=("一双臭袜子",),name="小李")    t1.start()    t2.start()    t1.join()    t2.join()# ==== 执行结果 ===="""小王将一封情书放在了寄存柜里...小李将一双臭袜子放在了寄存柜里...三个月后,小王忽然想起了自己有件东西放在柜子里,决定取出来最后他从自己的柜子里取出来了: 一封情书三个月后,小李忽然想起了自己有件东西放在柜子里,决定取出来最后他从自己的柜子里取出来了: 一双臭袜子"""

原理分析

我们可以自己做一个全局字典,来实现与这个类似的功能,但是使用起来肯定不太方便(它实际上本质就是字典嵌套进行存储的):

import threadingimport timeLocker = {}  # 好了寄存柜放在全局了"""{线程id:{"article":"存放的具体物品"},线程id:{"article":"存放的具体物品"},线程id:{"article":"存放的具体物品"},}"""def operate(name):    """操作"""    print("三个月后,{0}忽然想起了自己有件东西放在柜子里,决定取出来".format(name))    ident = threading.get_ident()  # 获取线程ID    print("最后他从自己的柜子里取出来了:",Locker[ident]["article"])def people(article):    name = threading.current_thread().getName()  # 获取线程名    ident = threading.get_ident()  # 获取线程ID    Locker[ident] = {}  # 创建了一个寄存柜的小格子    Locker[ident]["article"] = article  # 这就表示将私有的的一件物品放在了寄存柜里    print("{0}将{1}放在了寄存柜里...".format(name,article))    time.sleep(3)  # 过了三个月,这期间发生了很多事    operate(name)if __name__ == '__main__':    t1 = threading.Thread(target=people,args=("一封情书",),name="小王")    t2 = threading.Thread(target=people,args=("一双臭袜子",),name="小李")    t1.start()    t2.start()    t1.join()    t2.join()# ==== 执行结果 ===="""小王将一封情书放在了寄存柜里...小李将一双臭袜子放在了寄存柜里...三个月后,小李忽然想起了自己有件东西放在柜子里,决定取出来最后他从自己的柜子里取出来了: 一双臭袜子三个月后,小王忽然想起了自己有件东西放在柜子里,决定取出来最后他从自己的柜子里取出来了: 一封情书"""

尝试自己做出一个寄存柜

这样做是不是太麻烦了?我们可以自定义一个类,让它变得更加简单,如同原本的使用方法一样。其实下面代码中采取的方法也是 threading.local() 所采取的方法。

import threadingimport timeclass MyLocker(object):    cabinet = {}  # 柜子    """    {    线程id:{"article":"存放的具体物品"},    线程id:{"article":"存放的具体物品"},    线程id:{"article":"存放的具体物品"},    }    """    def __getattr__(self, item):        """当访问属性不存在时触发"""        ident = threading.get_ident()        return MyLocker.cabinet[ident][item]    def __setattr__(self, key, value):        """试图用 . 去设置属性时触发"""        ident = threading.get_ident()        if ident in MyLocker.cabinet:  # 如果在柜子里这重新赋值            MyLocker.cabinet[ident][key] = value        else:            MyLocker.cabinet[ident] = {key: value}  # 如果不在则做一个小格子,并且把物件存放进来def operate(name):    """操作"""    print("三个月后,{0}忽然想起了自己有件东西放在柜子里,决定取出来".format(name))    print("最后他从自己的柜子里取出来了:", Locker.article)def people(article):    name = threading.current_thread().getName()  # 获取线程名    Locker.article = article  # 这就表示将私有的的一件物品放在了寄存柜里    print("{0}将{1}放在了寄存柜里...".format(name, article))    time.sleep(3)  # 过了三个月,这期间发生了很多事    operate(name)if __name__ == '__main__':    Locker = MyLocker()  # 好了寄存柜放在全局了    t1 = threading.Thread(target=people, args=("一封情书",), name="小王")    t2 = threading.Thread(target=people, args=("一双臭袜子",), name="小李")    t1.start()    t2.start()    t1.join()    t2.join()# ==== 执行结果 ===="""小王将一封情书放在了寄存柜里...小李将一双臭袜子放在了寄存柜里...三个月后,小王忽然想起了自己有件东西放在柜子里,决定取出来最后他从自己的柜子里取出来了: 一封情书三个月后,小李忽然想起了自己有件东西放在柜子里,决定取出来最后他从自己的柜子里取出来了: 一双臭袜子"""
import tkinter as tkimport socketimport threadingclass ChatClient: def __init__(self, host, port): self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.connect((host, port)) self.buffer_size = 1024 def send_msg(self, msg): self.sock.send(msg.encode('utf-8')) def recv_msg(self): data = self.sock.recv(self.buffer_size) return data.decode('utf-8')class ChatApp: def __init__(self, master): self.master = master master.title('ChatBot') self.chat_client = None self.msg_listbox = tk.Listbox(master) self.msg_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) self.msg_entry = tk.Entry(master) self.msg_entry.bind('<Return>', self.send_msg) self.msg_entry.pack(side=tk.BOTTOM, fill=tk.X, expand=True) self.connect_button = tk.Button(master, text='Connect', command=self.connect) self.connect_button.pack(side=tk.TOP) self.disconnect_button = tk.Button(master, text='Disconnect', command=self.disconnect, state=tk.DISABLED) self.disconnect_button.pack(side=tk.TOP) self.quit_button = tk.Button(master, text='Quit', command=self.quit) self.quit_button.pack(side=tk.TOP) def connect(self): self.chat_client = ChatClient('localhost', 5000) self.connect_button.config(state=tk.DISABLED) self.disconnect_button.config(state=tk.NORMAL) threading.Thread(target=self.recv_msg).start() def disconnect(self): self.chat_client.sock.close() self.connect_button.config(state=tk.NORMAL) self.disconnect_button.config(state=tk.DISABLED) def send_msg(self, event): msg = self.msg_entry.get() self.msg_entry.delete(0, 'end') self.msg_listbox.insert(tk.END, 'You: {}'.format(msg)) self.chat_client.send_msg(msg) def recv_msg(self): while True: data = self.chat_client.recv_msg() if not data: break self.msg_listbox.insert(tk.END, 'Bot: {}'.format(data)) def quit(self): if self.chat_client: self.chat_client.sock.close() self.master.destroy()if __name__ == '__main__': root = tk.Tk() app = ChatApp(root) root.mainloop()此代码在哪里输入IP地址及端口号
最新发布
05-25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值