20240718--创建线程的另外一种方式

1、创建线程的另外一种方式

1.1、之前创建线程方式:

import threading

def task_1(num):
    pass
t = threading.Thread(target = 函数名,args = (11,),kwargs = {"xx":yyy}
t.start() # 真正的创建线程




threading.enumrate()  #查看数量

1.2、另一种方式--封装性更好的一种创建线程的方式--封装类

使用类的方式创建线程

import threading
class UDP(threading.Thread):
    def run(self):
        pass





u_t = UDP()
# u_t.run()
u_t.start()

1.3、使用类创建子线程demo

import threading
import time
class Task(threading.Thread):
    def run(self):
        while True:
            print("11111")
            time.sleep(1)


t = Task()
t.start()

while True:
    print("main")
    time.sleep(1)

运行结果:

11111和main是一起出来的

11111

main

main

11111

小结:

  1. 可以自己定义一个类,但是这个类要继承Thread
  2. 一定要实现run方法,即要定义一个run方法,并且实现线程需要执行的代码。
  3. 当调用自己编写的类创建出来的实例对象的run方法时,会创建新的线程,并且线程会自动调用run方法。
  4. 如果除了run方法之外,还定义了其他的方法,例如xx,那么这些方法需要在run方法中自己去调用,线程自己不会调用。例如self.xx()
  5. 私有属性在子类里面不能被调用

2、并发TCP服务器

并发--同一时刻为多个项目服务,一起服务叫并发

import socket
import threading


class HandleData(threading.Thread):
    def __init__(self, client_socket):
        super().__init__()
        self.client_socket = client_socket

    def run(self):
        # 接收/发送数据
        while True:
            recv_content = self.client_socket.recv(1024)
            if len(recv_content) != 0:
                print(recv_content)
                self.client_socket.send(recv_content)
            else:
                self.client_socket.close()
                break

    def __del__(self):
        self.client_socket.close()



class TCPServer(threading.Thread):
    def __init__(self, port):
        # 调用父类的初始化方法
        # threading.Thread.__init__(self)
        super().__init__()

        # 创建套接字
        self.server_s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        # 绑定本地信息
        self.server_s.bind(("", port))

        # 将套接字由默认的主动链接模式改为被动模式(监听模块)
        self.server_s.listen(128)


    def run(self):
        # 等待客户端进行链接
        while True:
            new_s, client_info = self.server_s.accept()
            print(client_info)

            # t = HandleData(new_s)
            # t.start()
            HandleData(new_s).start()

    def __del__(self):
        # 关闭套接字
        self.server_s.close()


def main():
    tcp_server = TCPServer(7788)  # 7788表示TCP要绑定的端口
    tcp_server.start()

if __name__ == '__main__':
    main()

    小结:

  1. 可以通过定义一个新的类,继承threading.Thread的方式创建线程
  2. 创建这个线程对象的时候,可以像使用普通的类一样,给它的__init__方法创建参数
  3. __init__方法中通过super().__init__()调用被覆盖的父类方法,能够保证父类需要进行的准备工作能够正常执行
  4. 可以在__del__方法中调用close()关闭套接字

3、队列(Queue)

3.1、为什么使用队列?

多任务线程很多时候需要相互配合才能完成一件事情,例如,一个线程专门用来接收数据,另外一个线程专门用来存储刚刚接收的数据,如果需要将以上2个线程相互配合那么理论上来说,效率会很高。但是线程中的变量各自是各自的,为了能够让多个线程之间共享某些数据,就可以使用队列来实现数据共享。

3.2、什么是队列?

程序中一种特殊的存储数据的方式,可以实现先存入数据,先出去。

3.3、如何使用?

3.3.1、队列Queue--->先进先出的

往队列里放东西用---->put

import queue

q = queue.Queue()
q.put("11")  # 存入字符串
q.put(22)  # 存入整数
q.put({'num': 100})  # 存入字典

print(q.get())  # 11
print(q.get())  # 22
print(q.get())  # {'num': 100}

小结:

  1. 先进先出(FIFO)
  2. 可以存放任意类型数据,例如整数、字符串、字典
  3. 存入使用put(),取出使用get()(如果当前队列中没有数据、此时会堵塞)

3.3.2、堆栈Queue----->后进的先出

import queue

q = queue.LifoQueue()
q.put('11')  # 存入字符串
q.put(22)  # 存入整数
q.put({'num': 100})  # 存入字典

print(q.get())  # {'num': 100}
print(q.get())  # 22
print(q.get())  # 11

小结:

  1. LIFO-->后进先出
  2. 可以存放任意数据类型
  3. 存入使用put(),取出使用get()(如果当前队列中没有数据、此时会堵塞)

3.3.3、优先级Queue

放的时候要放元组,第一个元素表示优先级,数字越小,优先级越高;第二个元素表示要存放的数据。

import queue

q = queue.PriorityQueue()
q.put((10, 'Q'))
q.put((30, 'Z'))
q.put((20, 'A'))

print(q.get())  # (10, 'Q')
print(q.get())  # (20, 'A')
print(q.get())  # (30, 'Z')




小结:

  • 存放的数据是元组类型,第1个元素表示优先级,第2个元素表示存储的数据
  • 优先级数字越小优先级越高
  • 数据优先级高的优先被取出
  • 用于VIP用户数据优先被取出场景,因为上面两种都要挨个取出

4、带有聊天记录的UDP聊天程序

创建三个线程,一个队列


import socket
import threading
import queue


class SendMsg(threading.Thread):

    def __init__(self, udp_socket, queue):
        super().__init__()
        self.udp_socket = udp_socket
        self. queue = queue


    def run(self):
        """获取键盘数据,并将其发送给对方"""
        while True:
            print("1: 发送数据")
            print("2: 退出程序")
            op = input("请输入操作序号:")
            if op == "1":
                # 1. 输入对方的ip地址
                dest_ip = input("\n请输入对方的ip地址:")
                # 2. 输入对方的port
                dest_port = int(input("\n请输入对方的port:"))
                while True:
                    # 3. 从键盘输入数据
                    msg = input("\n请输入要发送的数据:")
                    if msg:
                        # 4. 发送数据
                        self.udp_socket.sendto(msg.encode("utf-8"), (dest_ip, dest_port))
                        info = "<<<(%s, %d):%s\n" % (dest_ip, dest_port, msg)
                        self.queue.put(info)
                    else:
                        # 要是没有输入内容则认为是要重新输入ip、port
                        break
            elif op == "2":
                break

    def __del__(self):
        self.udp_socket.close()


class RecvMsg(threading.Thread):
    def __init__(self, udp_socket, queue):
        super().__init__()
        self.udp_socket = udp_socket
        self.queue = queue

    def run(self):
        """接收数据并显示"""
        while True:
            try:
                # 1. 接收数据
                recv_msg = self.udp_socket.recvfrom(1024)
            except:
                break
            else:
                # 2. 解码
                recv_ip = recv_msg[1]
                recv_msg = recv_msg[0].decode("utf-8")
                # 3. 显示接收到的数据
                info = ">>>%s:%s\n" % (str(recv_ip), recv_msg)
                print(info)
                self.queue.put(info)

    def __del__(self):
        self.udp_socket.close()


class SaveChat(threading.Thread):
    def __init__(self, queue):
        super().__init__()
        self.queue = queue

    def run(self):
        while True:
            with open("./chat.txt", "a") as f:
                chat_info = self.queue.get()
                print("正在将(%s)写入到聊天记录文件中" % chat_info)
                f.write(chat_info)


def main():
    # 创建套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 绑定本地信息
    udp_socket.bind(("", 7890))

    # 创建一个FiFo的队列
    q = queue.Queue()

    # 创建线程对象
    udp_r = RecvMsg(udp_socket, q)
    udp_s = SendMsg(udp_socket, q)
    chat_thread = SaveChat(q)

    # 运行创建的子线程
    udp_r.start()
    udp_s.start()
    chat_thread.start()

if __name__ == "__main__":
    main()

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值