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

死锁

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

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

  • 29
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值