Python笔记五--多线程

本文介绍Python中多线程的基本概念与使用方法,包括线程创建、启动及线程间资源共享等,并通过示例讲解如何利用线程锁解决多线程数据同步问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

进程是CPU调度的基本单位,线程是进程内部进行CPU调度的基本单位,一个进程至少存在一个线程。
模块:threading
创建线程:Thread(target=func[args=(value1,value2,…)])
target:线程需要执行的任务(函数或者方法名)
args:指定线程执行的任务需要传入的实参,以元组形式传入
启动线程:start()
多线程之间是共享资源的,所以:

  • 线程可以被抢占(中断)。
  • 在其他线程正在运行时,线程可以暂时搁置(也称为睡眠) – 这就是线程的退让。

示例1:

def print_time(threadName,delay):
    count =0
    while count <5:
        time.sleep(delay)
        count +=1
        print(f"{threadName}:{time.ctime(time.time())}")

if __name__ == '__main__':
    th1 = threading.Thread(target=print_time,args=("th1",0.2,))
    th2 = threading.Thread(target=print_time,args=("th2",0.5,))
    th1.start()
    th2.start()

执行结果:
在这里插入图片描述

示例2:

import threading   #引入线程包
import time        #引入时间的包

def task1(num):  #任务1,例子中num--->5
    for i in range(num): #循环打印task1:数字
        print("task1:%d" % i)
        time.sleep(0.5)

def task2(num):#任务2,例子中num--->6
    for i in range(num):#循环打印task2:数字
        print("task2:%d" % i)
        time.sleep(0.5)

def main():#定义主函数
    """创建启动线程"""
    t1 = threading.Thread(target=task1, args=(5,))  #创建一个线程,target--》分配任务(给一个函数task1)
    t2 = threading.Thread(target=task2, args=(6, ))#创建一个线程,target--》分配任务(给一个函数task2)
    t1.start()    #t1进程启动
    t2.start()    #t2进程启动
    t1.join()   #我要等待t1全部执行完毕,才会执行后面的代码
    t2.join()   #我要等待t2全部执行完毕,才会执行后面的代码


if __name__ == '__main__':
    main()       #调用主函数,两个join保证全部线程执行完毕后,才会让主线程执行print.
    print("Done!")

执行结果:
在这里插入图片描述

线程锁:

多线程的优势在于可以同时运行多个任务(至少感觉起来是这样)。但是当线程需要共享数据时,可能存在数据不同步的问题。
比如:一个列表里所有元素都是0,线程"set"从后向前把所有元素改成1,而线程"print"负责从前往后读取列表并打印。那么,可能线程"set"开始改的时候,线程"print"便来打印列表了,输出就成了一半0一半1,这就是数据的不同步。为了避免这种情况,引入了锁的概念。

示例1:使用两个线程来模拟模拟两个人使用同一个账户井发取钱操作
import threading
import time


def count_num(account,num):
    # global lock
    # lock.acquire()  # 获得锁
    if account > num:  # 全局变量
        print(threading.current_thread().name + "取钱成功,吐出钞票:"+ str(num))
        account -= num
        print("账户余额为:"+ str(account))
    else:
        print(threading.current_thread().name + "账户余额不足,取钱失败")

if __name__ == '__main__':
    #lock = threading.Lock()  # 声明了一个锁对象
    # for i in range(10):
    #     t = threading.Thread(target=count_num,args=(1000,800))
    #     t.start()
    th1 = threading.Thread(target=count_num,args=(1000,800))
    th2 = threading.Thread(target=count_num,args=(1000,800))
    th1.start()
    th2.start()
    print("线程执行结束")
    ```
多次运行,可能会出现如下错误
![在这里插入图片描述](https://img-blog.csdnimg.cn/4b41a95bfec644acafd0300d12663997.png)
	很明显,这并不是期望看到的结果。为了保证数据的正确性,需要对多个线程进行同步。使用线程锁可以实现简单的线程同步,这两个对象都有acquire方法和release方法,对于那些每次只允许一个线程操作的数据,可以将其操作放到acquire和release方法之间。
	示例:
	

```python
import threading
import time


def count_num(account,num):
    global lock
    lock.acquire()  # 获得锁
    if account > num:  # 全局变量
        print(threading.current_thread().name + "取钱成功,吐出钞票:"+ str(num))
        account -= num
        print("账户余额为:"+ str(account))
    else:
        print(threading.current_thread().name + "账户余额不足,取钱失败")
    lock.release()  #释放锁

if __name__ == '__main__':
    lock = threading.Lock()  # 声明了一个锁对象
    # for i in range(10):
    #     t = threading.Thread(target=count_num,args=(1000,800))
    #     t.start()
    th1 = threading.Thread(target=count_num,args=(1000,800))
    th2 = threading.Thread(target=count_num,args=(1000,800))
    th1.start()
    th2.start()
    print("线程执行结束")

但是数据安全是以降低程序的运行效率作为代价的,为了减少线程安全所带来的负面影响,程序可以采用如下策略:
不要对线程安全类的所有方法都进行同步,只对那些会改变竞争资源(也就是共享资源)的方法进行同步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值