python 多任务之多线程

多线程

线程是程序执行的最小单位,实际上进程只负责分配资源,而利用这些资源执行程序的是线程,也就是说进程是线程的容器,一个进程中最少有一个线程来负责执行程序,它可以与同属一个进程的其它线程共享进程所拥有的全部资源

 

为什么要选择线程,而不选择进程

进程:就像同时和两个人聊QQ,就需要打开两个QQ软件,会占用没必要的资源

线程:就像同时和两个人聊QQ,只需要打开两个窗口就可以了,也会节省很多资源

 

线程的创建步骤

1.导入所需要的线程模块
import threading

2.通过线程类创建线程对象
线程对象 = threading.Thread(target=任务名)

3.启动线程
线程对象.start()

 

多线程的使用

import threading
import time

def eat():
    for i in range(5):
        print('正字吃饭=============')
        time.sleep(0.5)        # 等待0.5秒后再执行


def music():
    for i in range(5):
        print('正在唱歌=============')
        time.sleep(0.5)       # 等待0.5秒后再执行


if __name__ == '__main__':

    eat_thread = threading.Thread(target=eat,)
    music_thread = threading.Thread(target=music,)

    eat_thread.start()
    music_thread.start()

执行结果

9c37548225bf485e87a7074091b6ef7d.png

 

线程执行任务函数的传参

  • 元组方式传参:元组方式传参一定要和参数的顺序保持一致
  • 字典方式传参:字典方式传参字典中的key一定要和参数名保持一致
import threading
import time

def eat(num, name):
    for i in range(num):
        print(f'{name}正字吃饭=============')
        time.sleep(0.5)        # 等待0.5秒后再执行


def music(num, name):
    for i in range(num):
        print(f'{name}正在唱歌=============')
        time.sleep(0.5)       # 等待0.5秒后再执行


if __name__ == '__main__':

    eat_thread = threading.Thread(target=eat, args=(3, '张三'))
    music_thread = threading.Thread(target=music, kwargs={'num': 5, 'name': '李四'})

    eat_thread.start()
    music_thread.start()

执行结果

4b68f729761a49a087abf43ea2e986ca.png

 

守护主线程

主线程会等待所有的子线程执行结束后主线程再结束,但是也是可以主线程不等待子线程执行完成,可以设置守护主线程

两种方式

        1、threading.Thread(target=work, daemon=True)
        2、线程对象.setDaemon(True)

不设置守护主线程的情况下

import threading
import time

def eat():
    for i in range(10):
        print('正在吃饭==========')
        time.sleep(0.5)

if __name__ == '__main__':
    # 创建子线程
    eat_thread = threading.Thread(target=eat,)
    # 启动子线程
    eat_thread.start()
    time.sleep(2)
    print('主线程执行完毕========')

执行结果

f72bfe0294c24f8196ba8219d3992400.png

方式一守护主线程

import threading
import time

def eat():
    for i in range(10):
        print('正在吃饭==========')
        time.sleep(0.5)

if __name__ == '__main__':
    # 创建子线程
    eat_thread = threading.Thread(target=eat, daemon=True)
    # 启动子线程
    eat_thread.start()
    time.sleep(2)
    print('主线程执行完毕========')

执行结果

5bd2e2a5ba544ff3960d93a17fc2bc26.png

方式二守护主线程

import threading
import time

def eat():
    for i in range(10):
        print('正在吃饭==========')
        time.sleep(0.5)

if __name__ == '__main__':
    # 创建子线程
    eat_thread = threading.Thread(target=eat,)
    # 需要写在开启子线程前面
    eat_thread.setDaemon(True)
    # 启动子线程
    eat_thread.start()
    time.sleep(2)
    print('主线程执行完毕========')

执行结果

5a8827d6caf14c738de645239e8e8ef0.png

 

线程的执行顺序

一个进程里面,多个线程在执行,线程的执行是无序的,是由CPU调度决定某个线程先执行

获取当前线程的信息

1、通过current_thread方法获取线程对象的信息,例如被创建的顺序
current_thread_info = threading.current_thread()

print(current_thread_info)

import threading
import time

def thread_info():

    time.sleep(0.5)

    current_thread_info = threading.current_thread()
    print(current_thread_info)

if __name__ == '__main__':

    for i in range(5):
        sub_thread = threading.Thread(target=thread_info,)
        sub_thread.start()

执行结果

18399294b3cd4791b928890ec68e2e0b.png

 

线程间共享全局变量

多个线程都是在同一个进程中,多个线程使用的资源都是同一个进程中的资源,因此多线程间是共享全局变量

import time
import threading

def write_date():
    for i in range(3):
        my_list.append(i)
    print('这是子线程写入的表:', my_list)

def read_date():
    print('这是子线程读数据:', my_list)

my_list = []
if __name__ == '__main__':

    write_thread = threading.Thread(target=write_date)
    read_thread = threading.Thread(target=read_date)

    write_thread.start()
    time.sleep(1)
    read_thread.start()
    time.sleep(1)

    print('这是主线程读的数据:', my_list)

执行结果

b397a28e67364eb0ad84a5e5714bd36e.png

 

线程之间共享全局变量数据出现错误问题

解决办法

  • 同步:就是协同步调,按预定的先后次序进行运行。比如现实生活中的对讲机,你说一句我说一句,不能一起说
  • 使用线程同步:也就是互斥锁,同一时刻只能有一个线程去操作全局变量

不使用的情况下

import threading

# 定义全局变量
num = 0

def sum_num1():
    for i in range(1000):
        global num
        num += 1
    print('num1:', num)

def sum_num2():
    for i in range(1000):
        global num
        num += 1
    print('num2:', num)

if __name__ == '__main__':

    sum1 = threading.Thread(target=sum_num1,)
    sum2 = threading.Thread(target=sum_num2,)

    sum1.start()
    sum2.start()

执行结果

551170087d1d49cfb3ec417c2b8cd514.png

把num加大

import threading

# 定义全局变量
num = 0

def sum_num1():
    for i in range(1000000):      # 多加了几个0
        global num
        num += 1
    print('num1:', num)

def sum_num2():
    for i in range(1000000):       # 多加了几个0
        global num
        num += 1
    print('num2:', num)

if __name__ == '__main__':

    sum1 = threading.Thread(target=sum_num1, )
    sum2 = threading.Thread(target=sum_num2, )

    sum1.start()
    sum2.start()

执行结果

9d36e411c39e45bca5b6b981aa49e3de.png

 

互斥锁的使用

对共享数据进行锁定,保证同一时刻只有一个线程去操作

互斥锁是多个线程一起去抢,抢到锁的线程先执行,没有抢到的线程进行等候,等锁使用完释放后,其它等待的线程再去抢这个锁

使用

1、创建互斥锁
mutex  = threading.Lock()
2、上锁
mutex .acquire()
3、释放锁
mutex .release()

import time
import threading

# 定义全局变量
num = 0

def sum_num1():
    # 上锁
    mutex.acquire()
    for i in range(1000000):
        global num
        num += 1
    print('num1:', num)
    # 释放锁
    mutex.release()

def sum_num2():
    # 上锁
    mutex.acquire()
    for i in range(1000000):
        global num
        num += 1
    print('num2:', num)
    # 释放锁
    mutex.release()

if __name__ == '__main__':
    # 创建锁
    mutex = threading.Lock()
    # 创建子线程
    sum1 = threading.Thread(target=sum_num1, )
    sum2 = threading.Thread(target=sum_num2, )
    # 启动子线程
    sum1.start()
    sum2.start()

    time.sleep(5)
    print(num)

执行结果

 09a331ddb60b4268b08ce07325bd20b0.png

死锁

一直等待对方释放锁的情况就是死锁,死锁会造成程序的停止响应,不能再处理其他任务

产生死锁的原因:没有及时或者在正确的位置释放锁

 

 

相关推荐

  1. python线

    2024-06-09 20:32:02       42 阅读
  2. python 线

    2024-06-09 20:32:02       27 阅读
  3. Python任务编程-07线版udp聊天程序

    2024-06-09 20:32:02       53 阅读
  4. python线介绍

    2024-06-09 20:32:02       66 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-09 20:32:02       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-09 20:32:02       106 阅读
  3. 在Django里面运行非项目文件

    2024-06-09 20:32:02       87 阅读
  4. Python语言-面向对象

    2024-06-09 20:32:02       96 阅读

热门阅读

  1. Ubuntu22.04嵌入开发环境之NFS文件系统

    2024-06-09 20:32:02       28 阅读
  2. 力扣面试题17.18.最短超串

    2024-06-09 20:32:02       34 阅读
  3. leetcode 1514.概率最大的路径

    2024-06-09 20:32:02       32 阅读
  4. C语言中的变量和常量是什么,以及它们的区别

    2024-06-09 20:32:02       22 阅读
  5. cocos入门8:向量叉乘

    2024-06-09 20:32:02       33 阅读
  6. Mybatis-plus 自动填充字段

    2024-06-09 20:32:02       29 阅读
  7. 345_C++_共享缓冲区管理类shared_buffer

    2024-06-09 20:32:02       27 阅读