【6】python3线程之间相互通讯方式之队列Queue

一.接着上一篇文章,实现了客户端和服务器端通讯,那么,客户端与客户端之间可以相互发送消息吗,大学的时候记得有个c语言项目是这样实现的:客户端和服务器端之间用tcp连接并记录客户端ip和端口号,客户端和客户端用udp连接发送消息(客户端ip和端口号从服务器端获取)。

    今天试下利用队列实现客户端和客户端发送消息。
    原理:多个客户端同时在线,服务器端会产生多个线程,那么这些线程之间可以利用队列Queue实现相互发送消息。

二. 先看下队列怎么使用,如下代码:queue_test.py

from queue import Queue
from threading import Thread
import time

class Student(Thread):
    def __init__(self, name, queue):
        super().__init__()
        self.name = name
        self.queue = queue

    def run(self):
        while True:
            # 阻塞程序,时刻监听老师,接收消息
            msg = self.queue.get()
            # 一旦发现点到自己名字,就赶紧答到
            if msg == self.name:
                print("{}:到!".format(self.name))
            else:
                pass
                #self.queue.put(msg)


class Teacher:
    def __init__(self, queue):
        self.queue=queue

    def call(self, student_name):
        print("老师:{}来了没?".format(student_name))
        # 发送消息,要点谁的名
        self.queue.put(student_name)

if __name__ == "__main__":
    
    queue = Queue()
    teacher = Teacher(queue=queue)
    s1 = Student(name="小明", queue=queue)
    s2 = Student(name="小亮", queue=queue)
    s1.start()
    s2.start()

    print('开始点名~')
    teacher.call('小明')
    time.sleep(1)
    teacher.call('小亮')
    time.sleep(1)
    teacher.call('小明')
    time.sleep(1)

运行结果如下:
在这里插入图片描述
代码中将两个线程加到队列中,
s1 = Student(name=“小明”, queue=queue)
s2 = Student(name=“小亮”, queue=queue)注意这个顺序对于后面的调用非常重要。

为了效果我们把 开始点名那个地方代码替换下面的代码:

	print('开始点名~')
	teacher.call('小亮')
    time.sleep(1)
	teacher.call('小明')
    time.sleep(1)
    teacher.call('小亮')
    time.sleep(1)

运行结果如下:
在这里插入图片描述
结果中却没有出现学生喊到,为什么呢,没错,因为队列,小明的线程排在第一个,所有不管老师喊谁,小明第一个取数据发现不是自己不打印到,接着小亮,再小明…这样就会出现上面老师点名没有一个学生到。我们可以做个小修改,在小明一个取数据发现不是自己的时候,将数据重新放到队列中,让其他人取。
student类中添加else如下:

# 一旦发现点到自己名字,就赶紧答到
            if msg == self.name:
                print("{}:到!".format(self.name))
            else:
                self.queue.put(msg)

结果如下:
在这里插入图片描述
思考,如果点名不在这个队列中,如小花,会怎样呢。当然会导致代码出现死循环
修改queue_test.py代码如下:

from queue import Queue
from threading import Thread
import time

all_student = list()

class Student(Thread):
    global all_student
    def __init__(self, name, queue):
        super().__init__()
        self.name = name
        self.queue = queue
        all_student.append(name)
    def run(self):
        while True:
            # 阻塞程序,时刻监听老师,接收消息
            msg = self.queue.get()
            # 一旦发现点到自己名字,就赶紧答到
            if msg == self.name:
                print("{}:到!".format(self.name))
            else:
                
                if all_student.__contains__(msg):
                    print(msg)
                    self.queue.put(msg)
                    time.sleep(0.001)


class Teacher:
    def __init__(self, queue):
        self.queue=queue

    def call(self, student_name):
        print("老师:{}来了没?".format(student_name))
        # 发送消息,要点谁的名
        self.queue.put(student_name)
def main():
    queue = Queue()
    teacher = Teacher(queue=queue)
    s1 = Student(name="小明", queue=queue)
    s2 = Student(name="小亮", queue=queue)
    s1.start()
    s2.start()

    print('开始点名~')
    teacher.call('小话')
    time.sleep(1)
    teacher.call('小亮')
    time.sleep(1)
    teacher.call('小明')
    time.sleep(1)
    teacher.call('小亮')
    time.sleep(1)
    s3 = Student(name="小话", queue=queue)
    s3.start()
    teacher.call('小话')
    time.sleep(1)
    teacher.call('小亮')
    time.sleep(1)
    teacher.call('小明')

if __name__ == "__main__":
    main()
    

添加全局变量all_student = list(),存放student线程,如果点名不在student线程中就不put数据到队列中。
总结:队列先进先出,先取数据。如上问题,点名小花,会导致代码死循环,可以设置标志,当重新遇到自己线程设置的标志位就暂停put数据到队列中。下一章基于这个原理实现socket客户端之间相互发送消息
上一篇:【5】python和android之间socket传输protobuf数据
下一篇:【7】python3 客户端之间相互发送消息

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奔走的小龙虾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值