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()