从线程类调用时,Python函数的行为不符合预期

时间:2013-02-12 14:54:13

标签: python python-2.7 thread-safety minecraft python-multithreading

我正在尝试使用适用于Python 2.7的新Minecraft Pi Edition API编写游戏。当我意识到代码的两个部分相互阻塞时,我几乎完成了游戏。如果我首先放置A部分,它将阻止B部分运行,直到A部分完成。如果我把B部分放在第一位,它会很慢地运行。我决定将两个部分分成两个独立的线程。 “

这是仍然存在问题的代码的缩减版本。我注意到如果我为两个类中的一个注释掉ClassName.start()行,那么另一个类将运行而不会出错。

import mcpi.minecraft as minecraft
import threading

mc = minecraft.Minecraft.create()

class BlockCheckThread(threading.Thread):
    def run(self):
        while True:
            event = mc.events.pollBlockHits()

class WinningCheckThread(threading.Thread):
    def run(self):
        while True:
            blockTest = mc.getBlock(1, 1, 1,) == 50

def main():
    WinningCheckThread().start() # If I comment out either of these .start() lines
    BlockCheckThread().start()   # the other class executes perfectly.

运行此错误如下:

Exception in thread Thread-2:
...
TypeError: Hit() takes exactly 5 arguments (1 given)

Exception in thread Thread-1:
...
ValueError: invalid literal for int() with base 10: '

要运行代码,您需要一个Raspberry Pi,并且需要从here下载Minecraft,然后您必须从api/python/目录运行它。 (即它必须与它导入的mcpi模块位于同一文件夹中。)

这是我第一次尝试线程化,所以不要在我的代码上大笑。我很想知道为什么这段代码不起作用,以及我应该怎么做才能解决它。

2 个答案:

答案 0 :(得分:4)

您正在共享Minecraft对象,并且它不是线程安全的。 Minecraft对象只是一个客户端库,用于连接到使用命令minecraft-pi启动的Minecraft服务器。您需要为每个线程创建一个Minecraft对象,它应该没问题:

import mcpi.minecraft as minecraft
import threading

class BlockCheckThread(threading.Thread):
    def run(self):
        mc = minecraft.Minecraft.create()
        while True:
            event = mc.events.pollBlockHits()

class WinningCheckThread(threading.Thread):
    def run(self):
        mc = minecraft.Minecraft.create()
        while True:
            blockTest = mc.getBlock(1, 1, 1,) == 50

def main():
    WinningCheckThread().start() 
    BlockCheckThread().start()   

答案 1 :(得分:3)

Pi Edition的Python Minecraft客户端不是线程安全的。会发生什么是两个线程同时发送和接收数据。当响应混淆时(即BlockCheckThread获得对WinningCheckThread请求的响应,反之亦然),消息格式与线程期望获得的格式不匹配。

您可以简单地在Minecraft客户端的每次调用周围放置一个lock,以确保您一次只发送和接收一个项目。

我不知道Minecraft服务器是否支持它,但您也可以send multiple requests。为此,您需要一个能够跟踪未完成请求顺序的经理类。