2019年12月19日
一.概念
1.进程
image.png2.线程
image.png3.多线程开发 推荐用threading
image.pngimport threading
# 当前线程对象
t = threading.current_thread()
# 当前线程名
print(t.name)
# 返回当前处于活动状态的线程个数
print(threading.active_count())
# 当主线程对象
t = threading.main_thread()
# 主线程名
print(t.name)
image.png
二.创建线程
image.png1.方法1创建线程
# coding=utf-8
import threading
import time
# 线程体函数
def thread_body():
# 当前线程对象
t = threading.current_thread()
for n in range(2):
# 当前线程名
print('第{0}次执行线程{1}'.format(n, [t.name](http://t.name/)))
# 线程休眠
time.sleep(1)
print('线程{0}执行完成!'.format(t.name))
# 主函数
def main():
# 创建线程对象t1
t1 = threading.Thread(target=thread_body)
# 启动线程t1
t1.start()
# 创建线程对象t2
t2 = threading.Thread(target=thread_body, name='MyThread')
# 启动线程t2
t2.start()
if __name__ == '__main__':
main()
休眠可以看出是交替执行
image.png2.方法2创建线程 (继承线程类)
# coding=utf-8
import threading
import time
class MyThread(threading.Thread):
def __init__(self, name=None):
super().__init__(name=name)
# 线程体函数
def run(self):
# 当前线程对象
t = threading.current_thread()
for n in range(2):
# 当前线程名
print('第{0}次执行线程{1}'.format(n, t.name))
# 线程休眠
time.sleep(1)
print('线程{0}执行完成!'.format(t.name))
# 主函数
def main():
# 创建线程对象t1
t1 = MyThread()
# 启动线程t1
t1.start()
# 创建线程对象t2
t2 = MyThread(name='MyThread')
# 启动线程t2
t2.start()
if __name__ == '__main__':
main()
三.线程的管理 (等待线程结束和线程停止)
image.png1.等待线程结束例子(join)
# coding=utf-8
import threading
import time
# 共享变量
value = 0
# 线程体函数
def thread_body():
global value
# 当前线程对象
print('ThreadA 开始...')
for n in range(2):
print('ThreadA 执行...')
value += 1
# 线程休眠
time.sleep(1)
print('ThreadA 结束...')
# 主函数
def main():
print('主线程 开始...')
# 创建线程对象t1
t1 = threading.Thread(target=thread_body, name='ThreadA')
# 启动线程t1
t1.start()
# 主线程被阻塞,等待t1线程结束
t1.join()
print('value = {0}'.format(value))
print('主线程 结束...')
if __name__ == '__main__':
main()
image.png
2.线程停止 (while循环的需要添置,通过全局变量来控制)
# coding=utf-8
import threading
import time
# 线程停止变量
isrunning = True
# 线程体函数
def thread_body():
while isrunning:
# 线程开始工作
# TODO
print('下载中...')
# 线程休眠
time.sleep(5)
print('执行完成!')
# 主函数
def main():
# 创建线程对象t1
t1 = threading.Thread(target=thread_body)
# 启动线程t1
t1.start()
# 从键盘输入停止指令 exit
command = input('请输入停止指令:')
if command == 'exit':
global isrunning
isrunning = False
if __name__ == '__main__':
main()
image.png
四.线程安全
1.临界资源问题
image.png销售机票例子(错误的例子)
# coding=utf-8
import threading
import time
class TicketDB:
def __init__(self):
# 机票的数量
self.ticket_count = 5
# 获得当前机票数量
def get_ticket_count(self):
return self.ticket_count
# 销售机票
def sell_ticket(self):
# TODO 等于用户付款
# 线程休眠,阻塞当前线程,模拟等待用户付款
time.sleep(1)
print("第{0}号票,已经售出".format(self.ticket_count))
self.ticket_count -= 1
# 创建TicketDB对象
db = TicketDB()
# 线程体1函数
def thread1_body():
global db # 声明为全局变量
while True:
curr_ticket_count = db.get_ticket_count()
# 查询是否有票
if curr_ticket_count > 0:
db.sell_ticket()
else:
# 无票退出
break
# 线程体2函数
def thread2_body():
global db # 声明为全局变量
while True:
curr_ticket_count = db.get_ticket_count()
# 查询是否有票
if curr_ticket_count > 0:
db.sell_ticket()
else:
# 无票退出
break
# 主函数
def main():
# 创建线程对象t1
t1 = threading.Thread(target=thread1_body)
# 启动线程t1
t1.start()
# 创建线程对象t2
t2 = threading.Thread(target=thread2_body)
# 启动线程t2
t2.start()
if __name__ == '__main__':
main()
有问题 两个5了
image.png2.多线程同步[解决上面数据出错的问题]
image.png# coding=utf-8
import threading
import time
class TicketDB:
def __init__(self):
# 机票的数量
self.ticket_count = 5
# 获得当前机票数量
def get_ticket_count(self):
return self.ticket_count
# 销售机票
def sell_ticket(self):
# TODO 等于用户付款
# 线程休眠,阻塞当前线程,模拟等待用户付款
time.sleep(1)
print(threading.current_thread().name)
print("第{0}号票,已经售出".format(self.ticket_count))
self.ticket_count -= 1
# 创建TicketDB对象
db = TicketDB()
# 创建Lock对象
lock = threading.Lock()
# 线程体1函数
def thread1_body():
global db, lock # 声明为全局变量
while True:
lock.acquire()
curr_ticket_count = db.get_ticket_count()
# 查询是否有票
if curr_ticket_count > 0:
db.sell_ticket()
else:
lock.release()
# 无票退出
break
lock.release()
time.sleep(1)
# 线程体2函数
def thread2_body():
global db, lock # 声明为全局变量
while True:
lock.acquire()
curr_ticket_count = db.get_ticket_count()
# 查询是否有票
if curr_ticket_count > 0:
db.sell_ticket()
else:
lock.release()
# 无票退出
break
lock.release()
time.sleep(1)
# 主函数
def main():
# 创建线程对象t1
t1 = threading.Thread(target=thread1_body)
# 启动线程t1
t1.start()
# 创建线程对象t2
t2 = threading.Thread(target=thread2_body)
# 启动线程t2
t2.start()
if __name__ == '__main__':
main()
image.png
五.线程之间通信
通信可以使用threading模块的Condition 和 Event类
1.Condition
image.png# coding=utf-8
import threading
import time
# 创建条件变量对象
condition = threading.Condition()
class Stack:
def __init__(self):
# 堆栈指针初始值为0
self.pointer = 0
# 堆栈有5个数字的空间
self.data = [-1, -1, -1, -1, -1]
# 压栈方法
def push(self, c):
global condition
condition.acquire()
# 堆栈已满,不能压栈
while self.pointer == len(self.data):
# 等待其它线程把数据出栈
condition.wait()
# 通知其他线程把数据出栈
condition.notify()
# 数据压栈
self.data[self.pointer] = c
# 指针向上移动
self.pointer += 1
condition.release()
# 出栈方法
def pop(self):
global condition
condition.acquire()
# 堆栈无数据,不能出栈
while self.pointer == 0:
# 等待其他线程把数据压栈
condition.wait()
# 通知其他线程压栈
condition.notify()
# 指针向下移动
self.pointer -= 1
data = self.data[self.pointer]
condition.release()
# 数据出栈
return data
# 创建堆栈Stack对象
stack = Stack()
# 生产者线程体函数
def producer_thread_body():
global stack # 声明为全局变量
# 产生10个数字
for i in range(0, 10):
# 把数字压栈
stack.push(i)
# 打印数字
print('生产:{0}'.format(i))
# 每产生一个数字线程就睡眠
time.sleep(1)
# 消费者线程体函数
def consumer_thread_body():
global stack # 声明为全局变量
# 从堆栈中读取数字
for i in range(0, 10):
# 从堆栈中读取数字
x = stack.pop()
# 打印数字
print('消费:{0}'.format(x))
# 每消费一个数字线程就睡眠
time.sleep(1)
# 主函数
def main():
# 创建生产者线程对象producer
producer = threading.Thread(target=producer_thread_body)
# 启动生产者线程
producer.start()
# 创建消费者线程对象consumer
consumer = threading.Thread(target=consumer_thread_body)
# 启动消费者线程
consumer.start()
if __name__ == '__main__':
main()
正常现象
image.png2.Event
image.png# coding=utf-8
import threading
import time
event = threading.Event()
class Stack:
def __init__(self):
# 堆栈指针初始值为0
self.pointer = 0
# 堆栈有5个数字的空间
self.data = [-1, -1, -1, -1, -1]
# 压栈方法
def push(self, c):
global event
# 堆栈已满,不能压栈
while self.pointer == len(self.data):
# 等待其它线程把数据出栈
event.wait()
# 通知其他线程把数据出栈
event.set()
# 数据压栈
self.data[self.pointer] = c
# 指针向上移动
self.pointer += 1
# 出栈方法®
def pop(self):
global event
# 堆栈无数据,不能出栈
while self.pointer == 0:
# 等待其他线程把数据压栈
event.wait()
# 通知其他线程压栈
event.set()
# 指针向下移动
self.pointer -= 1
# 数据出栈
data = self.data[self.pointer]
return data
# 创建堆栈Stack对象
stack = Stack()
# 生产者线程体函数
def producer_thread_body():
global stack # 声明为全局变量
# 产生10个数字
for i in range(0, 10):
# 把数字压栈
stack.push(i)
# 打印数字
print('生产:{0}'.format(i))
# 每产生一个数字线程就睡眠
time.sleep(1)
# 消费者线程体函数
def consumer_thread_body():
global stack # 声明为全局变量
# 从堆栈中读取数字
for i in range(0, 10):
# 从堆栈中读取数字
x = stack.pop()
# 打印数字
print('消费:{0}'.format(x))
# 每消费一个数字线程就睡眠
time.sleep(1)
# 主函数
def main():
# 创建生产者线程对象producer
producer = threading.Thread(target=producer_thread_body)
# 启动生产者线程
producer.start()
# 创建消费者线程对象consumer
consumer = threading.Thread(target=consumer_thread_body)
# 启动消费者线程
consumer.start()
if __name__ == '__main__':
main()
正常现象
image.png如果您发现本文对你有所帮助,如果您认为其他人也可能受益,请把它分享出去。
网友评论