网络编程基础 多任务 第一讲(未完待续)

这篇博客介绍了多任务的基本概念,包括并发与并行的区别,并详细讲述了Python中实现多任务的线程方式,包括线程介绍、线程创建与执行、守护线程、t.join()的使用、查看线程数量以及线程间的通信。
摘要由CSDN通过智能技术生成

多任务 第一讲

一、多任务

1.多任务介绍

同时做多件事情(多个任务)就叫多任务。

2.多任务理解

在这里插入图片描述
CPU有单核、双核和四核的,即便是单核也可以同时进行多任务处理,这是因为CPU通过时间片轮转调度的模式来进行作业,同一个程序在CPU当中快速处理完毕会退出来,为下一个程序腾出空间进行处理。

  1. 并发:CPU数量小于当前的执行的任务。是假的多任务
  2. 并行:CPU数量大于当前执行的任务。是真的多任务

3.实现多任务的三种方式

  1. 线程
  2. 进程
  3. 协程

二、线程

1.线程介绍

线程(thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。

2.使用线程完成多任务

举个例子:

import time
import threading # 内置模块

def demo(): # 这里叫子线程
    print('1111')
    time.sleep(1)

if __name__ == '__main__':
	# for循环目的是为了创建多个线程对象
    for i in range(3):
    	# 线程实例化,target参数为调用的函数名,如果函数需要置入参数则要添加args=(),详细内容看说明文档
        t = threading.Thread(target=demo) # 这里叫主线程
        # 启动线程
        t.start()

上面的函数效果会让多个线程同时运行,即实现多任务的功能,函数中所设置的tim.sleep(1)是为了做前后对比,在使用多线程后,3次循环内容会全部输出再同时沉睡1秒(自己试试就知道了)。

理解上我们需要注意的是,for循环的目的是为了创建多个线程对象,每次循环并不会紧接着启动线程(即执行t.start),会等待线程对象全部创建完毕再启动所有线程,从而实现多线程同时运行的功能

写一段伪代码看一看,如何实现多个任务:

import time
import threading

def exercise():
    for i in range(3):
        print(f'我正在锻炼第{i}次')
        time.sleep(1)
        
def listen_to_music():
    for i in range(3):
        print(f'我正在听第{i}首歌')
        time.sleep(1)
        
if __name__ == '__main__':
    t1 = threading.Thread(target=exercise)
    t2 = threading.Thread(target=listen_to_music)

    t1.start()
    t2.start()
----------------------------------
输出结果:
我正在锻炼第0# 两个线程同时执行
我正在听第0首歌  #
我正在听第1首歌
我正在锻炼第1次
我正在锻炼第2次
我正在听第2首歌

注意:
主线程退出后子线程的状态依赖于它所在的进程,如果进程没有退出的话子线程依然正常运转。如果进程退出了,那么它所有的线程都会退出,所以子线程也就退出了。
主线程退出,进程等待所有子线程执行完毕后才结束。

我们可以将一个py文件看做一个进程(虽然还没学习到进程,可以简单理解为一个进程包含多个线程),上面的注意事项我们通过一段代码来进行讲解:

import threading
import time

def demo():
    for i in range(3):
        print('hello world')
        time.sleep(1)

if __name__ == '__main__':
    t = threading.Thread(target=demo)  # 主线程
    t.start()
    print('---1---')
-------------------------------
输出结果:
hello world
---1---
hello world
hello world

上述结果可以看出,主线程执行完完毕后打印输出---1---,子线程仍然在运行。

3.守护线程

当设置一个线程为守护线程时,此线程所属进程不会等待此线程运行结束,进程将立即结束。

同样使用上一节代码:

import threading
import time

def demo():
    for i in range(3):
        print('hello world')
        time.sleep(1)

if __name__ == '__main__':
    t = threading.Thread(target=demo)
    t.setDaemon(True)  # 将主线程设置为守护线程
    t.start()
    print('---1---')
-----------------------------
输出结果:
hello world
---1---

可以看出,子线程并未持续执行。

4. t.join()的用法

t.join()所完成的工作就是线程同步,即主线程任务结束之后,进入阻塞状态,一直等待其他的子线程执行结束之后,主线程再终止。

import threading
import time

def demo():
    for i in range(3):
        print('hello world')
        time.sleep(1)

if __name__ == '__main__':
    t = threading.Thread(target=demo)
    t.start()
    t.join() # 注意,一定要在start之后,否则会报错
    print('---1---')
-------------------------------
输出结果:
hello world
hello world
hello world
---1---

从上述结果可以看出,在子线程执行完毕后才打印输出---1---,说明子线程执行完毕后主线程才退出。

join方法有一个参数timeout,它的作用:

  1. 当设置守护线程时,含义是主线程对于子线程等待timeout的时间将会杀死该子线程,最后退出程序。所以说,如果有10个子线程,全部的等待时间就是每个timeout的累加和。简单的来说,就是给每个子线程一个timeout的时间,让他去执行,时间一到,不管任务有没有完成,直接杀死。
  2. 当设置守护线程时,含义是主线程对于子线程等待timeout的时间将会杀死该子线程,最后退出程序。所以说,如果有10个子线程,全部的等待时间就是每个timeout的累加和。简单的来说,就是给每个子线程一个timeout的时间,让他去执行,时间一到,不管任务有没有完成,直接杀死。

5.查看线程数量

使用方法threading.enumerate()来查看当前线程的数量。

import threading
import time

def demo1():
    for i in range(3):
        print(f'demo1第{i}次打印')
        time.sleep(1)

def demo2():
    for i in range(3):
        print(f'demo2第{i}次打印')
        time.sleep(1)

def main():
    t1 = threading.Thread(target=demo1)
    t2 = threading.Thread(target=demo2)

    t1.start()
    t2.start()
    print(threading.enumerate())

if __name__ == '__main__':
    main()
---------------------------
输出结果:
demo1第0次打印
demo2第0次打印
[<_MainThread(MainThread, started 2412)>, <Thread(Thread-1, started 12132)>, <Thread(Thread-2, started 17608)>]
demo2第1次打印demo1第1次打印

demo1第2次打印
demo2第2次打印

Process finished with exit code 0

打印结果显示有一个主线程,两个子线程。

6.验证子线程的执行与创建

当调用Thread的时候,不会创建线程。
当调用Thread创建出来的实例对象的start方法的时候,才会创建线程以及开始运行这个线程。
(记住就好,不再验证)

7.继承Thread类创建线程

创建方法如下:

import threading
import time

# 1.继承Thread类
class A(threading.Thread):
    # 2.改写类中的run方法,但是不要修改方法名
    def run(self):
        for i in range(3):
            print(i)
            time.sleep(1)

if __name__ == '__main__':
    # 3.创建实例化对象
    t = A()
    # 4.运行线程
    t.start()

如果在A类中有定义其它方法,那么需要在run方法中才可以实现。

8.多线程共享全局变量(线程之间的通信)

通过下述代码我们可以演示一下:

import threading
import time

num = 100

def demo1():
    global num      # 2.声明为全局变量
    num += 1        # 1.函数作用域 访问不到外边的num 所以报错 找不到 
    print(f"demo----{num}")


def demo2():
    print(f"demo1----{num}")


def main():
    t1 = threading.Thread(target=demo1)
    t2 = threading.Thread(target=demo2)
    t1.start()
    time.sleep(1)
    t2.start()
    time.sleep(1)
    
    
if __name__ == '__main__':
    main()
-------------------------------------
输出结果:
demo----101
demo1----101
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值