新人第一次提问, 最近在学习Python多线程, notify()与wait()语句。这是我写的一个作业, 要求是:
现在的你,是一个农场主。农场中养着10头小牛,牛吃草长大,但只有当下雨的时候草才会长大,每天有20%的概率下雨,草经过3次成长后就可以喂给牛吃了。每头小牛吃过5次草之后就会长大了。要求使用多线程来完成。小牛(消费者)线程和草(生产者)之间需要通信。
以下是我的代码:
import threading
import random
from time import sleep
"""
声明全局变量:
num_cows: 牛的数量, 整形,十头。
cows: 牛的集合, 列表(数组)。 长度:10
num_grass: 草的数量, 整形,若干。 区间:50-101棵。 为了确保每头牛都可以长大,小草必须至少有50棵。
grass: 草的集合, 列表(数组)。 长度:num_grass
initial_stat: 草/牛的初始状态,整形,设置为0。
increment: 用于改变状态的变量,整形,设置为0。
"""
# 定义全局变量
num_cows, initial_stat, num_grass = 10, \
0, \
random.randint(50, 101)
cows, grass = [], []
for i in range(num_grass): # 设置草儿数量,初始化每一棵小草状态
grass.append(initial_stat)
for i in range(num_cows): # 初始化每一头牛
cows.append(initial_stat)
# TODO 草儿生长类
class GrassGrow(threading.Thread):
"""草成长线程"""
# TODO 重写run函数
def run(self):
global grass
global cows
while True:
ct.acquire()
print("一天过去了...小草会不会生长呢?")
grass = rain(grass) # 淋雨的草儿成长一次,数位进一, 呼叫rain函数, 传入参数grass列表
if len(grass) > 0: # 判断还有没有需要生长的草儿
if grassgrow(grass): # 检查草儿,若有一株淋到三次雨,通知牛儿吃草
print("提醒牛儿该吃草了")
ct.notify() # 提醒牛儿线程该吃草了
ct.release()
print("草线程解锁")
sleep(1)
print("通知牛儿吃草了")
elif len(grass) <= 0: # 如果草儿被吃完了,结束进程
print("草儿被吃光啦")
ct.release() # 解锁
break # 退出程序
# TODO 牛儿生长类
class CowGrow(threading.Thread):
"""牛儿成长线程"""
print("start")
# TODO 重写run函数
def run(self):
print("1")
global cows
global grass
# TODO 随机一头牛吃草
while True:
print("2")
ct.acquire()
print("3")
ct.wait()
print("4")
if grassgrow(grass) and 5 not in cows:
print("牛有草能吃了")
# 长大的小草中,随机吃掉一株,从草儿列表中移除
index = []
for i in range(len(grass)):
if grass[i] >= 3:
index.append(i)
delete = index[random.randint(0, len(index) - 1)]
del grass[delete]
cows[random.randint(range(len(cows)))] += 1 # 随机一头牛吃草,状态进1
print("有一头牛把吃了一颗草,现在的牛儿们是:{}".format(cows))
# 判断牛儿中是否有长大的牛儿
elif 5 in cows:
# 移除所有已经长大的牛儿
for cow in range(len(cows)):
if cows[cow] == 5:
del cows[cow]
# 判断是不是所有的牛儿都长大了,如果都长大了,结束进程
elif len(cows) == 0:
print("所有的牛儿都长大啦")
ct.release()
break
ct.wait()
ct.release()
# sleep(1)
# TODO 下雨函数
def rain(grass_list):
"""
:param grass_list: 接收 草儿列表作为参数
:return: 返回 新的,淋雨之后的草儿列表
"""
# 遍历草列表中的每一株草
rain_probability = random.randint(1, 101)
# 每天有20%几率局部下雨。如果未下雨,则所有小草都不会成长。如果下雨了,局部小草会成长。
if rain_probability <= 20:
for a_grass in range(len(grass_list)):
grass_grow_prob = random.randint(1, 101)
if grass_grow_prob <= 50 and 0 <= grass_list[a_grass] <= 2:
grass_list[a_grass] += 1
print("今天下雨啦,现在的小草们:{}".format(grass))
print("今天没有下雨,没有小草生长...")
return grass_list
# TODO 判断草长大函数
def grassgrow(grass_list):
"""
:param grass_list: 接收 草儿列表作为参数
:return: 返回 若有生长好的小草则返回真,否则为假
"""
if 3 not in grass_list:
print("目前为止还没有小草生长完成")
return False
else:
print("有小草生长完成了,现在的小草们:{}".format(grass))
return True
if __name__ == "__main__":
ct = threading.Condition() # 定义线程变量, 用于多线程通信
cow_thread = CowGrow()
grass_thread = GrassGrow()
cow_thread.start()
print("牛等待吃草")
grass_thread.start()
rain函数用来20%几率下雨, grasgrow函数用来判断有没有草淋了三次雨, 一旦有草淋到三次雨就可以了通知CowGrow线程吃草了。
我的解题思路是: 创建一个列表grass代表草, 一个列表cows代表牛。类GrassGrow中当判断grassgrow函数为真时, 唤醒牛线程。然后随机一头牛吃了一颗草之后,阻塞自己等待。而当我实际运行的时候,牛在一开始被阻塞之后一直没有被唤醒
以下是运行结果:
start
1
2
3牛等待吃草
一天过去了...小草会不会生长呢?
今天没有下雨,没有小草生长...
目前为止还没有小草生长完成
一天过去了...小草会不会生长呢?
今天下雨啦,现在的小草们:[1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1]
今天没有下雨,没有小草生长...
目前为止还没有小草生长完成
一天过去了...小草会不会生长呢?
今天没有下雨,没有小草生长...
目前为止还没有小草生长完成
一天过去了...小草会不会生长呢?
今天下雨啦,现在的小草们:[1, 1, 1, 0, 0, 2, 1, 1, 1, 2, 0, 0, 1, 1, 2, 1, 2, 2, 1, 0, 1, 1, 0, 1, 2, 1, 0, 2, 1, 1, 0, 1, 2, 1, 1, 0, 1, 0, 2, 1, 2, 2, 2, 0, 0, 2, 1, 2, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 2, 1, 1, 1, 2, 1, 2, 2, 1, 2, 1, 1, 2, 1, 0, 1, 1, 2, 2, 2, 0, 2, 1, 2, 1, 2, 1, 0, 1, 0, 2, 1, 1, 1, 2, 1, 1, 1]
今天没有下雨,没有小草生长...
目前为止还没有小草生长完成
一天过去了...小草会不会生长呢?
今天下雨啦,现在的小草们:[2, 2, 1, 1, 1, 2, 2, 1, 2, 2, 1, 0, 1, 1, 2, 2, 2, 3, 2, 1, 1, 1, 0, 1, 2, 2, 1, 2, 2, 2, 0, 1, 3, 1, 2, 0, 1, 0, 3, 2, 3, 3, 3, 0, 1, 2, 1, 2, 0, 1, 1, 2, 2, 1, 0, 1, 1, 1, 1, 3, 1, 1, 1, 3, 2, 2, 3, 1, 2, 2, 1, 3, 2, 1, 1, 2, 3, 2, 2, 1, 2, 1, 3, 1, 2, 2, 1, 1, 0, 3, 2, 2, 1, 3, 2, 2, 1]
今天没有下雨,没有小草生长...
有小草生长完成了,现在的小草们:[2, 2, 1, 1, 1, 2, 2, 1, 2, 2, 1, 0, 1, 1, 2, 2, 2, 3, 2, 1, 1, 1, 0, 1, 2, 2, 1, 2, 2, 2, 0, 1, 3, 1, 2, 0, 1, 0, 3, 2, 3, 3, 3, 0, 1, 2, 1, 2, 0, 1, 1, 2, 2, 1, 0, 1, 1, 1, 1, 3, 1, 1, 1, 3, 2, 2, 3, 1, 2, 2, 1, 3, 2, 1, 1, 2, 3, 2, 2, 1, 2, 1, 3, 1, 2, 2, 1, 1, 0, 3, 2, 2, 1, 3, 2, 2, 1]
提醒牛儿该吃草了
草线程解锁
通知牛儿吃草了
一天过去了...小草会不会生长呢?
可以看到牛只有一开始调用了一次...之后再也没有被唤醒, 而且前几次小草没有sleep就运行了好多次,之后才开始运行sleep,打印"提醒牛儿该吃草了", "草线程解锁", "通知牛儿吃草了"才开始运行。谷歌和本站都查了一些问题,但和我的情况都不太相似。真心像各位请教...拜托了..