python多线程编程有两个模块,分别是_thread模块和threading模块。
现在我们一般都使用threading模块。
一、threading模块多线程编程的基本知识
threading.Thread(target, name=None, args=() ) :该函数的作用是创建子线程(主函数的线程叫主线程,其他的线程都为子线程)。
target表示为线程体(线程本是函数对象)。
name用来决定线程的名字,不输入或输入None,系统会帮你自动分配名字。
args:用于给函数对象传参数,以元组的形式传参-----传一个参数,args=(3,)
对于子线程而言,创建了以后还需要启动。
用Thread类的start()方法来启动。
例:
t1 = threading.Thread(target=thread_test)
t1.start()
threading.current_thread():返回当前线程对象
threading.main_thread(): 返回主线程对象
threading.active_thread():返回当前活动的线程个数
线程对象的属性--常用的只有一个。
name:线程的名字
例:
t_main = threading.main_thread()
print(t_main.name)
主线程名字为MainThread
也就是说,输出为:MainThread
二、threading的condition类基本内容
condition类的一些方法:
acquire():给该线程体(函数对象)上锁,使其他线程不能进入(执行)该线程体---也叫互斥锁
release():给线程体释放锁
wait(setting):使当前线程体释放锁,并使当前线程体处于阻塞状态。等待其他线程唤醒或者超时后继续执行,setting是超时时间
notify(c):唤醒相同条件变量的一个线程,c是条件变量。
notify_all(c):唤醒相同条件变量的所有线程,c是条件变量。
三、使用condition类实现线程间通信
3.1 经典的堆栈算法---用两个不同的子线程分别进行压栈(也叫入栈)和出栈算法
如果栈已满,你继续压栈,该线程就会进入阻塞状态,就唤醒另一个线程进行出栈;出栈后,再唤醒之前的子线程,再压栈。
如果栈为空,也是一样。
还有一点,使用线程的话一般会使用time模块,使用time.sleep()方法来使线程休眠
上代码:
import threading
import time
condition = threading.Condition()
class Stack:
def __init__(self):
self.pointer = 0
self.data = [-1, -1, -1, -1, -1]
def get_stack_data_len(self): # 获取栈的长度
return len(self.data)
def get_stack_data(self): # 获取栈内数据
return self.data
# 压栈方法
def push(self, data):
global condition
condition.acquire() # 上锁
while self.pointer == len(self.data): # 栈已满
print('线程1等待中')
condition.wait() # 释放锁,并处于阻塞状态
condition.notify() # 通知其他线程,唤醒其他线程
self.data[self.pointer] = data
print('数据入栈:', data)
self.pointer += 1 # 指针上移
condition.release() # 解锁
time.sleep(1)
# 出栈方法
def pop(self):
global condition
condition.acquire()
while self.pointer == 0: # 栈已空
print('线程2等待中')
condition.wait()
condition.notify()
self.pointer -= 1
data = self.data[self.pointer]
print('数据出栈:',data)
self.data[self.pointer] = -1 # 出栈后,应将数据变为-1
condition.release()
return data
def menu():
print('1.入栈')
print('2.出栈')
print('3.栈长度')
print('4.栈内数据')
print('0.退出')
if __name__ == '__main__':
menu()
stack = Stack()
is_run = True
while is_run:
command = input('请输入选项:')
if command == '1':
data = int(input('请输入入栈的数据:'))
t1 = threading.Thread(target=stack.push, args=(data,))
t1.start()
time.sleep(1)
if command == '2':
t2 = threading.Thread(target=stack.pop)
t2.start()
time.sleep(1)
if command == '3':
print('栈长度:',stack.get_stack_data_len())
if command == '4':
print('栈内数据:', stack.get_stack_data())
if command == '0':
is_run = False
print('退出')
这个可以自己操作,自己观察。所以我改成了选项的模式来展现。
3.2 生产者和消费者
接下来还有一个:生产者和消费者的(相比于栈,略有改动)
import threading
import time
condition = threading.Condition()
class Stack:
def __init__(self):
self.pointer = 0
self.data = [-1, -1, -1, -1, -1]
# 压栈方法
def push(self, data):
global condition
condition.acquire() # 上锁
while self.pointer == len(self.data): # 栈已满
print('生产者等待中')
condition.wait() # 释放锁,并处于阻塞状态
condition.notify() # 通知其他线程,唤醒其他线程
self.data[self.pointer] = data
# print('数据入栈:', data)
self.pointer += 1 # 指针上移
condition.release() # 解锁
time.sleep(1)
# 出栈方法
def pop(self):
global condition
condition.acquire()
while self.pointer == 0: # 栈已空
print('消费者等待中。。。')
condition.wait()
condition.notify()
self.pointer -= 1
data = self.data[self.pointer]
# print('数据出栈:', data)
self.data[self.pointer] = -1 # 出栈后,应将数据变为-1
condition.release()
return data
stack = Stack()
def producer_thread_body():
global stack
for i in range(10): # 产生10个数据
stack.push(i) # 将数据压栈(入栈)
print('生产:{0}'.format(i))
# 每产生一个数据,线程就睡眠
time.sleep(1) # 睡眠1s
def consumer_thread_body():
global stack
for i in range(10):
data = stack.pop()
print('消费:{0}'.format(data))
time.sleep(1)
def main():
producer = threading.Thread(target=producer_thread_body, name='thread-1')
producer.start()
consumer = threading.Thread(target=consumer_thread_body, name='thread-2')
consumer.start()
if __name__ == '__main__':
main()
也就是消费者要买东西,
如果有就直接消费,
如果没有那就要等生产者生产后,再通知消费者来消费。
当然控制台输出可能有些出入,因为不同的线程同时输出的话会比较混乱。这个只能自己把握。