Python多任务--进程线程协程

b站视频笔记
-----------------------------------------------------------------------------------------------------------------------
一、线程
01 多任务介绍、Thread的基本使用
import time
import threading

def sing():
    """唱歌5秒"""
    for i in range(5):
        print("----正在唱歌----")
        time.sleep(1)

def dance():
    """跳舞5秒"""
    for i in range(5):
        print("----正在跳舞----")
        time.sleep(1)

def main():
    t1 = threading.Thread(target=sing)  # threading模块的Thread类,传参:函数名
    t2 = threading.Thread(target=dance)
    t1.start()  # 实例对象t1调用start方法,启动线程
    t2.start()

if __name__ == "__main__":
    main()

单核CPU:同一时刻只有一件事在做,并发:假的多任务 / 多核:并行:真的多任务,一个萝卜一个坑
操作系统调度方法:时间片轮转;优先级调度

02 Thread创建线程 完成多任务
03 查看正在运行的线程、主线程等待子线程先结束
import threading
import time

def test1():
    for i in range(5):
        print("-----test1---%d---" % i)
        time.sleep(1) # 线程执行顺序不确定,可以用延时控制

def test2():
    for i in range(10):
        print("-----test2---%d---" % i)
        time.sleep(1) # 线程在函数运行完以后结束

def main():
    t1 = threading.Thread(target=test1) # 当调用Thread的时候,不会创建线程
    t2 = threading.Thread(target=test2)

    t1.start() # 当调用Thread创建出来的实例对象的start方法时,才会创建线程以及让线程开始运行
    t2.start()

    while True:
        print(threading.enumerate())
        if len(threading.enumerate())<=1:
            break
        time.sleep(1)
# 子线程结束以后主线程不会结束,相反,主线程挂了,则子线程也结束
if __name__ == "__main__":
    main()

04 通过Thread类完成创建线程
import threading
import time

class MyThread(threading.Thread):
    def run(self): # start调用一定对应run方法
        for i in range(3):
            time.sleep(1)
            msg = "I'm "+ self.name + '@ '+str(i)
            # name属性中保存的时当前线程的名字
            print(msg)
            self.login() # 线程中想增加其他方法,用self.方法调用
            self.register()

    def login(self):
        print('这是登录')

    def register(self):
        print('这里注册')
if __name__ == '__main__':
    t = MyThread()
    t.start()
运行结果:
>>> I'm Thread-1@ 0
I'm Thread-1@ 1
I'm Thread-1@ 2

06 多线程:多线程之间是共享全局变量的
在一个函数中对全局变量进行修改的时候,到底是否需要使用global进行说明,要看是否对全局变量的执行指向进行了修改,
如果修改了指向,那么必须使用global,如果仅仅是修改了指向的空间中的数据,此时不用必须使用global

07 args参数
import threading
import time

def test1(temp):
    temp.append(33)
    print("-----in test1 temp=%s----" % str(temp))

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

g_nums = [11, 22]

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

    t1.start()
    time.sleep(1)

    t2.start()
    time.sleep(1)

    print("-----in main Thread g_nums = %s----" % str(g_nums))

if __name__ == "__main__":
    main()

08 共享全局变量会出现的问题--资源竞争
错误原因:还没做完,线程就被切换了
解决:原子性,要么不做,要么做完
同步:协同步调,按预定的先后顺序进行运行。
互斥锁:
# 创建锁
mutex = threading.Lock()
# 锁定
mutex.acquire()
# 释放
mutex.release()

10 死锁 银行家算法
不止一把互斥锁时可能出现,相互等待。
避免死锁:
1、添加超时时间
2、程序设计时要尽量避免(银行家算法)

11 多任务版UDP聊天器(同时收发消息)
补充:
socket套接字(网络通信必备)创建-收发-关闭
创建:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 创建tcp套接字
s= socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # 创建udp套接字

import socket
import threading

def recv_msg():
    """接收数据并显示"""
    # 接收数据
    while True:
        recv_data = udp_socket.recvfrom(1024)
        print(recv_data)

def send_msg():
    """发送数据"""
    # 发送数据
    while True:
        send_data = input("输入要发送的数据:")
        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.绑定本地信息
    udp_socket.bind(("", 7890))
    # 3.获取对方的IP
    dest_ip = input("请输入对方的IP:")
    dest_port = int(input("请输入对方的PORT:"))
    
    # 4.创建2个线程,去执行相应的功能
    t_recv = threading.Thread(target=recv_msg, args=(udp_socket,))
    t_send = threading.Thread(target=send_msg, args=(udp_socket, dest_ip, dest_port))

    t_recv.start()
    t_send.start()

if __name__ == "__main__":
    main()

二、进程
01 进程与程序
程序是死的,运行起来是进程,一个程序可以对应多个进程。进程是资源分配的单位,线程是资源调度的单位。
02 使用Process实现多进程
ps -aux 查看进程,PID是唯一的

import threading
import time
import multiprocessing

def test1():
    while True:
        print("1---")
        time.sleep(1)

def test2():
    while True:
        print("2---")
        time.sleep(1)

def main():
    p1 = multiprocessing.Process(target=test1)
    p2 = multiprocessing.Process(target=test2)
    p1.start() # 创建一个新进程,主进程有什么,子进程就有什么,写时拷贝,否则共享
    p2.start()

if __name__ == "__main__":
    main()

06 通过队列Queue获取进程间的数据 (先进先出)
put()放数据,get()取数据
1、数据共享 2、解耦
同一个程序,同一台主机
import multiprocessing

def download_from_web(q):
    """下载数据"""
    # 模拟从网上下载数据
    data = [11, 22, 33, 44]
    # 向队列中写入数据
    for temp in data:
        q.put(temp)
    print("---下载器已经下载完了数据并且存入到队列中----")

def analysis_data(q):
    """数据处理"""
    waitting_analysis_data = list()
    # 从队列中获取数据
    while True:
        data = q.get()
        waitting_analysis_data.append(data)

        if q.empty():
            break

    # 模拟数据处理
    print(waitting_analysis_data)

def main():
    # 1.创建一个队列
    q = multiprocessing.Queue()
    # 2.创建多个进程,将队列的引用当做实参进行传递到里面
    p1 = multiprocessing.Process(target=download_from_web, args=(q,))
    p2 = multiprocessing.Process(target=analysis_data)
    p1.start()
    p2.start()

if __name__ == "__main__":
    main()

07 进程池 Pool
当需要创建的子进程数量不多时,可以直接用multiprocessing中的Process动态生成多个进程,但如果是上百甚至上千个目标,手动创建工作量巨大。

08 多任务文件夹copy

三、协程
利用线程在等待的时间,去处理其他别的事情
#Python#
全部评论

相关推荐

投递阿里巴巴控股集团等公司7个岗位 >
点赞 评论 收藏
转发
点赞 4 评论
分享
牛客网
牛客企业服务