天天看点

python进阶(二)_多任务_线程单核多任务:时间片轮转;用户端感觉多个任务同步执行。线程:threading模块创建函数和类的线程global ** 修改全局变量互斥锁:多任务版udp聊天器

单核多任务:时间片轮转;用户端感觉多个任务同步执行。

  • 并行:真的多任务;任务数 <= cpu核数
  • 并发:假的多任务;任务数 > cpu核数

线程:threading模块

  • 线程:一个程序运行起来之后,一定有个执行代码的东西,这个东西就称为线程
  • enumerate 拆包:返回的是元组

创建函数和类的线程

threading.Thread(target = 函数名)     #创建函数的线程

class 类名(threading.Thread):       #创建类线程
    def run(self):
        pass
t = 类名()
t.start()                           # start调用run()
           

global ** 修改全局变量

  • 在一个函数中对全局变量修改时,如果修改了指向,即全局变量指向一个新的地方,那么必须使用global
  • 如果仅仅修改了指向空间的数据,此时可以不用global说明。
  • 示例代码:
import  threading
import time


g_num = 100
g_num2 = [11, 22]

def test1(temp):
    global  g_num
    g_num += 1
    print("-----in test1 g_num = %d-----" % g_num)
    temp.append(33)
    print("-----in test1 temp = %s-----" % str(temp))


def test2(temp):
    print("-----in test2 g_num = %d-----" % g_num)
    print("-----in test1 temp = %s-----" % str(temp))


def main():
    # target指定将来这个线程去哪个函数执行代码
    # args 指定将来调用函数的时候传递什么数据过去(实参) 数据是元组
    t1 = threading.Thread(target = test1, args=(g_num2,))
    t2 = threading.Thread(target = test2, args=(g_num2,))

    t1.start()
    time.sleep(1)
    t2.start()
    time.sleep(1)
    print("-----in main Threah g_num = %d-----" % g_num)
    print("-----in main Threah g_num2 = %s-----" % str(g_num2))


if __name__ == "__main__":
    main()
           
  • 运行结果
-----in test1 g_num = 101-----
-----in test1 temp = [11, 22, 33]-----
-----in test2 g_num = 101-----
-----in test1 temp = [11, 22, 33]-----
-----in main Threah g_num = 101-----
-----in main Threah g_num2 = [11, 22, 33]-----
[Finished in 2.5s]
           

互斥锁:

  • 当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制(上锁~解锁)
  • 注意避免死锁的方法:
    • 程序设计时要尽量避免(银行家算法)
    • 设置超时时间
  • 示例代码:
import threading
import time

# 定义全局变量
g_num = 0
mutex = threading.Lock()

def test1(num):
    global  g_num
    # 上锁,如果之前没有被上锁,那么此时上锁成功
    # 如果之前已经上锁,那么此时会堵塞,知道前一个锁解开
    for i in range(num):
        #mutex.acquire()
        g_num += 1
        # 解锁
        #mutex.release()
    print("-----in test1 g_num = %d-----" % g_num)


def test2(num):
    global g_num
    # 上锁,如果之前没有被上锁,那么此时上锁成功
    # 如果之前已经上锁,那么此时会堵塞,知道前一个锁解开

    for i in range(num):
        #mutex.acquire()
        g_num += 1
        # 解锁
        #mutex.release()
    print("-----in test2 g_num = %d-----" % g_num)


def main():
    t1 = threading.Thread(target=test1, args=(10000000,))
    t2 = threading.Thread(target=test2, args=(10000000,))

    t1.start()
    t2.start()
    time.sleep(5)
    print("-----in main Thread g_num = %d-----" % g_num)

if __name__ == '__main__':
    main()
           
  • 运行结果
-----in test1 g_num = 11246796-----
-----in test2 g_num = 11281556-----
-----in main Thread g_num = 11281556-----
[Finished in 5.2s]
           

多任务版udp聊天器

# 多任务版udp聊天器
import  socket
import  threading

def recv_msg(udp_socket):
    """接收并显示数据"""
    # 接接收数据
    while True:
        recv_data = udp_socket.recvfrom(1024)
        print(recv_data[0].decode("utf-8"))


def send_msg(dest_ip, dest_port,udp_socket):
    """发送数据"""
    while True:
        send_data = input("请输入要发送的数据:\n")
        udp_socket.sendto(send_data.encode("utf-8"), (dest_ip, dest_port))


def main():
    """完成udp聊天的整体控制"""

    # 1.创建套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    # 2.绑定本地信息
    dest_ip0 = input("请输入自己的ip:")
    dest_port0 = int(input("请输入自己的port:"))
    localaddr = (dest_ip0, dest_port0)
    udp_socket.bind(localaddr)

    # 3.获取对方地址
    dest_ip1 = input("请输入对方的ip:")
    dest_port1 = int(input("请输入对方的port:"))

    # 4.创建2个线程,去执行相应的功能
    t_recv = threading.Thread(target = recv_msg,args = (udp_socket,))
    t_send = threading.Thread(target = send_msg,args =(dest_ip1, dest_port1,udp_socket))

    t_recv.start()
    t_send.start()


           

Python下的多线程处理

Python多线程的原理与实现