从线程类调用时,Python函数表现不如预期

2 投票
2 回答
725 浏览
提问于 2025-04-17 15:37

我正在用新的Minecraft Pi Edition API为Python 2.7写一个游戏。游戏快完成的时候,我发现代码的两个部分互相干扰。如果我先写部分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: '

要运行这个代码,你需要一台树莓派,并且需要从这里下载Minecraft。然后你必须从api/python/目录运行它。(也就是说,它必须和你要导入的mcpi模块在同一个文件夹里。)

这是我第一次尝试使用线程,所以别太嘲笑我的代码。我想知道为什么这段代码不工作,以及我该怎么修复它。

2 个回答

3

Python的Minecraft客户端在Pi版上不是线程安全的。这是什么意思呢?就是有两个线程同时在发送和接收数据。当这两个线程的响应搞混了,比如说BlockCheckThread收到了WinningCheckThread的请求的响应,反之亦然,这样就会导致消息格式和线程预期的不一致。

为了避免这种情况,你可以在每次调用Minecraft客户端的时候加一个,这样可以确保每次只发送和接收一条信息。

我不确定Minecraft服务器是否支持这个功能,但你也许可以发送多个请求。不过这样的话,你需要一个管理类来跟踪这些请求的顺序。

4

你正在共享一个对象,但这个对象不是线程安全的。对象其实就是一个客户端库,用来连接通过命令启动的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()   

撰写回答