16 线程

1.多任务

在这里插入图片描述

2.多线程

在这里插入图片描述
在这里插入图片描述

3.互斥锁

在这里插入图片描述
在这里插入图片描述

4.同步

在这里插入图片描述

# 1.多任务:在同一时间内执行多个任务

# 多任务执行方式:
# 1.并发
# 2.并行

# 2. 进程和线程
# 2.1进程: 打开一个程序至少就会有一个进程,
#          操作系统进行资源分配的基本单位
# 一个进程默认有一个线程, 进程里面可以创建多个线程

# 2.2线程: 是进程中执行代码的一个分支,是CPU调度的基本单位


# 3. 单线程
# import time
# def sing():
#     print('思思在唱歌')
#     time.sleep(2)  # 睡眠,单位是秒
#     print('开演唱会')
#
#
# def dance(name):
#     print('%s在跳舞' % name)
#     time.sleep(2)
#     print('还在跳舞')
#
# sing()
# dance('张三')

# 4.多线程
# 线程模块: threading
# 4.1 线程类Thread参数:
#         target: 执行的目标任务名
#         args: 以元组的形式给任务传参
#         kwargs:以字典的形式给任务传参


# 4.2  步骤
# 1. 导入模块 threading
# 2.创建子线程 ,使用Thread类
# 3.开启子线程   start()

# import time
# import threading
#
# def sing(name):
#     print('%s在唱歌' % name)
#     time.sleep(2)  # 睡眠,单位是秒
#     print('开演唱会')
#
#
# def dance(name2):
#     print('%s在跳舞' % name2)
#     time.sleep(2)
#     print('还在跳舞')
#
#
# # 创建子线程, target : 只需要函数名
# t1 = threading.Thread(target=sing, args=('zs',))
# t2 = threading.Thread(target=dance, args=('zs',))
#
# # 开启子线程
# t1.start()
# t2.start()
#
#
# # 5. 方法
# import time
# from threading import Thread
#
# def funa():
#     print('面向对象')
#     time.sleep(2)
#     print('有点难')
#
# def funb():
#     print('农夫山泉')
#     time.sleep(2)
#     print('有点甜')
#
#
#
# if __name__ == '__main__':        #主程序入口,
# #如果有此行代码,文件被import导入后,这后面的代码不执行
#     # 1.创建子线程
#     f1 = Thread(target=funa)
#     f2 = Thread(target=funb)
#
#     # 3.setDaemon() : 守护线程
#     # 主线程执行完了,子线程也跟着结束(要放在start前面)
#     f1.setDaemon(True)
#     f2.setDaemon(True)
#
#     # 2.开启子线程
#     f1.start()
#     f2.start()
#
#     # 4. join() : 阻塞主线程
#     # 有暂停的作用,等添加join的子线程执行完,主线程才能继续执行 (放在start后面)
#     # 加了join,守护线程的功能还在,只是没有体现
#     # f1.join()
#     # f2.join()
#
#     # 6.修改名字
#     f1.setName('线程一')
#     f2.setName('线程二')
#     #
#     # # 5.获取名字
#     # print(f1.getName())
#     # print(f2.getName())
#     #
#     #
#     # print('这是主线程,程序的最后一行')


# 1.复习
import time
# from threading import Thread  # 导入线程模块
#
# def funa(name):
#     print('%s在哈哈笑' % name)
#     time.sleep(1)
#
#
# if __name__ == '__main__':
#
#     for i in range(4):
#         # 创建子线程
#         t1 = Thread(target=funa, args=('zs',))
#         # 开启线程
#         t1.start()

# 2. 线程执行代码的封装
# 线程类
# class MyThread(Thread):
#     def __init__(self, name):
#         super().__init__()  # 调用父类的init方法, 重写
#         self.name = name
#
#     # 重写run方法, 表示线程活动的方法
#     def run(self):
#         print('我是')
#         time.sleep(2)
#         print(self.name)
#
# if __name__ == '__main__':
#     # 创建一个线程实例
#     my = MyThread('zs')
#     # 启动线程,  start会调用run方法
#     my.start()

# 3.线程之间执行是无序的
# 3.1  线程之间执行是无序的,它是由CPU调度决定
# import threading
# def test():
#     time.sleep(1)
#     # 查看当前线程名
#     print('当前线程名:', threading.current_thread().name)
#
# if __name__ == '__main__':
#     for i in range(5):
#         # 创建子线程
#         s1 = threading.Thread(target=test)
#         # 开启子线程
#         s1.start()

5.线程资源共享和竞争

from threading import Thread
import time

# 举例一:
# 定义一个空列表
# li = []
#
# # 写数据
# def wdata():
#     for i in range(5):
#         li.append(i)
#         time.sleep(0.2)
#     print('写入的数据:', li)
#
# # 读数据
# def rdata():
#     print('读取的数据:', li)
#
# if __name__ == '__main__':
#     # 创建写入数据的子线程
#     wd = Thread(target=wdata)
#     # 创建读取数据的子线程
#     rd = Thread(target=rdata)
#     wd.start()
#     # time.sleep(1)
#     wd.join()
#     rd.start()        #只能读到一个数是因为上面wdata()中有个time.sleep(0.2),当睡眠的时候已经读完了
# 可以在wd.start后加sleep,给读取的时候腾出时间,尝试改sleep时间试试看效果
# 还可以加个wd.join(),有暂停的作用,等添加join的子线程执行完,主线程才能继续执行 (放在start后面)
# 就可以达到wd写完的效果
#     print('这是最后一行')
a = 0
b = 1000000


def jia():
    for i in range(b):
        global a
        a += 1
    print('第一次:', a)


def jia2():
    for i in range(b):
        global a
        a += 1
    print('第二次:', a)


if __name__ == '__main__':
    first = Thread(target=jia)
    second = Thread(target=jia2)
    first.start()
    second.start()

# 举例二: 资源共享导致的资源竞争
#
# a = 0
# b = 1000000
#
# def jia():
#     for i in range(b):
#         global a    # global声明全局变量
#         a += 1
#     print('第一次:', a)   # a = 1000000
#
#
# def jia2():
#     for i in range(b):
#         global a
#         a += 1
#     print('第二次:', a)  # a = 2000000
#
# if __name__ == '__main__':
#     # 创建子线程
#     first = Thread(target=jia)
#     second = Thread(target=jia2)
#     # 开启子线程
#     first.start()
#     second.start()

# 线程同步:一个任务执行完以后另一个任务才能执行,
#          同一时刻只有一个任务在执行
# 线程同步的方式: 线程等待join   、 互斥锁

# 互斥锁:对共享数据进行锁定
# 互斥锁多个线程一起去抢,抢到的线程先执行,没有抢到的线程需要等待

# 讲师房  A开门----进入以后----关门---开门
# ABC

# 互斥锁使用:
# 1.定义Lock变量
# 2.acquire(加锁)和release(解锁)方法之间的代码,同一时刻只能有一个线程去操作
# 3.必须成对出现,否则会造成死锁


# 举例一:
# from threading import Thread, Lock
# a = 0
# b = 1000000
# # 解决办法二:
# # 1.创建全局互斥锁
# lock = Lock()
#
# def jia():
#     lock.acquire()   # 2.加锁
#     for i in range(b):
#         global a    # global声明全局变量
#         a += 1
#     print('第一次:', a)   # a = 1000000
#     lock.release()   # 3.解锁
#
#
# def jia2():
#     lock.acquire()
#     for i in range(b):
#         global a
#         a += 1
#     print('第二次:', a)  # a = 2000000
#     lock.release()
#
# if __name__ == '__main__':
#     # 创建子线程
#     first = Thread(target=jia)
#     second = Thread(target=jia2)
#     # 开启子线程
#     first.start()
#     # 解决办法一:
#     # 等待第一个线程执行完以后再继续执行
#     # first.join()
#     second.start()
#
# 互斥锁
# 1.好处:确保某段关键代码只能由一个线程从头到尾完整的执行
# 2.会影响代码的执行效率,多任务变成了单任务执行
# 3.如果没有使用好容易出现死锁的情况

# 死锁:
# 1.一直等待对方释放锁的情景
# 2.会造成应用程序的停止响应,不能处理其他任务了

# 同步:
# 线程A和线程B, A是写入, B是读取A写入的内容; 而且需要A先执行完,B才能读取
# A和B之间就是一种同步关系
# 又来一个线程C, 也是写入, A和C之间就是一种互斥关系,因为同时只能由一个线程写入

# 举例二:
# 1. 输入密码,查看账户余额
# 2.输入取款金额
# 3.判断账户余额是否大于取款金额
# 4.大于的话,就取款成功; 小于的话,就取款失败

# import threading
# import time
#
# class Acount:
#     def __init__(self, ye):
#         self.ye = ye  # 账户余额
#         self.lock = threading.Lock()
#
#     def money(self, m_count):  # m_count  取出的金额
#         self.lock.acquire()   # 加锁
#         try:
#             if self.ye >= m_count:
#                 # threading.current_thread().name  当前线程名
#                 print(threading.current_thread().name, '取钱成功:', m_count)
#                 time.sleep(0.1)
#                 # 修改账户余额
#                 self.ye -= m_count
#                 print('当前余额:', self.ye)
#
#             else:
#                 print(threading.current_thread().name, '取钱失败,余额不足')
#                 print('当前余额:', self.ye)
#         finally:
#             self.lock.release()   # 解锁
#
# # 定义一个函数来模拟取钱操作
# def out_money(obj, data):
#     obj.money(data)   #   ac.money(800)
#
# if __name__ == '__main__':
#     ac = Acount(1000)   # 实例化对象
#
#     # 模拟两个线程对用一个账户取钱
#     # name属性设置线程名
#     t1 = threading.Thread(name='张三', target=out_money, args=(ac, 800))
#     t2 = threading.Thread(name='李四', target=out_money, args=(ac, 100))
#
#     t1.start()
#     t2.start()


import threading
import time


class Account:
    def __init__(self, balance):
        self.balance = balance
        self.lock = threading.Lock()

    def money(self, d_money):  # d_money 此次取钱数额
        self.lock.acquire()  # 取钱时开始加锁,实现单次只能一次取
        try:
            if self.balance >= d_money:
                print('The original amount: ', self.balance)
                print(threading.current_thread().name, 'Withdraw money successfully!The amount taken out is: ', d_money)
                time.sleep(0.1)  # 加sleep可以达到t1还没取完,t2就去取的效果,金额结果就会出现异常了
                # 加上互斥锁就可以解决这个问题
                self.balance -= d_money
                print('The remaining amount: ', self.balance)
            else:
                print(threading.current_thread().name, 'Your balance is lower than the amount of draw money,failed!')
                print('Current balance is: ', self.balance)
        finally:
            self.lock.release()  # 取完后就解锁


def draw_money(obj, amount):
    obj.money(amount)


if __name__ == '__main__':
    ac = Account(10000)
    # 模拟两个进程对一个账户取钱:
t1 = threading.Thread(name='李', target=draw_money, args=(ac, 4000))
t2 = threading.Thread(name='周', target=draw_money, args=(ac, 300))

t1.start()
t2.start()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值