目录
一.为什么要用队列
多个线程中,线程中的变量各自是各自的,为了能够让多个线程之间共享某些数据,就可以使用队列来实现数据共享。
二.队列Queue
先存入的会被先取出。
import queue
q = queue.Queue()
q.put('11') # 存入字符串
q.put(22) # 存入整数
q.put({'num': 100}) # 存入字典
print(q.get()) # 使用get()取数据,如果当前队列中没有数据,此时会堵塞
print(q.get())
print(q.get())
三.堆栈Queue
先存入的数据后取出
import queue
q = queue.LifoQueue()
q.put('11') # 存入字符串
q.put(22) # 存入整数
q.put({'num': 100}) # 存入字典
print(q.get())
print(q.get())
print(q.get())
四、优先级Queue
优先级越高的越先取出
import queue
q = queue.PriorityQueue()
q.put((10, '11')) # 存入字符串
q.put((30, 22)) # 存入整数
q.put((20, {'num': 100})) # 存入字典
print(q.get())
print(q.get())
print(q.get())
五、队列案例---带有聊天记录的UDP聊天程序
如果a线程需要向文件c写入"abc",b线程需要向文件c写入“123”.如果两个线程同时写入,那么就可能会写成a1b2c3,造成我们不想要的结果,如果有队列,a线程和b线程就会排队,依次写入自己的内容。
实现思路:
代码:
import threading
import socket
import queue
class RecvMsg(threading.Thread):
"""接收数据"""
def __init__(self, udp_s, q):
super().__init__()
self.udp_s = udp_s
self.q = q
def run(self):
while True:
recv_content, client_info = self.udp_s.recvfrom(1024)
temp_content = ">>>%s(%d):%s" % (client_info[0], client_info[1], recv_content.decode("gbk"))
print(temp_content)
self.q.put(temp_content)
def __del__(self):
self.udp_s.close()
class SendMsg(threading.Thread):
"""发送数据"""
def __init__(self, udp_s, q):
super().__init__()
self.udp_s = udp_s
self.q = q
def run(self):
while True:
dest_ip = input("请输入对方的ip")
dest_port = int(input("请输入对方的port:"))
while True:
send_content = input("请输入要发送的数据:")
if send_content:
self.udp_s.sendto(send_content.encode('gbk'), (dest_ip, dest_port))
temp_info = "<<<%s(%d):%s" % (dest_ip, dest_port, send_content)
self.q.put(temp_info)
else:
break
def __del__(self):
self.udp_s.close()
class ChatHistory(threading.Thread):
def __init__(self, q):
super(ChatHistory, self).__init__()
self.q = q
def run(self):
# 从Queue从取数据
content = self.q.get()
# 写入文件
with open("./chat.txt", "a") as f:
f.write(content)
f.write("\n") # 使内容可以换行
def main():
# 1、创建一个udp套接字
udp_s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 2、绑定本地信息
udp_s.bind(("", 7890))
# 创建一个FIFO的队列
q = queue.Queue()
# 3、创建一个新的线程对象,目的用来接收数据
recv_msg_thread = RecvMsg(udp_s, q)
# 4、创建一个新的线程对象,目的用来检测键盘发送数据
send_msg_thread = SendMsg(udp_s, q)
# 5、创建一个新的线程对象,目的用来存储聊天记录
chat_history_thread = ChatHistory(q)
recv_msg_thread.start()
send_msg_thread.start()
chat_history_thread.start()
if __name__ == '__main__':
main()