簡體   English   中英

Python - 線程同時打印,弄亂了文本輸出

[英]Python - Threads are printing at the same time messing up the text output

我在一個應用程序中使用了 4 個線程,這些線程返回我想打印給用戶的文本。 由於我想避免線程獨立打印這些文本,因此我創建了一個類來管理它...

我不知道我在這里做錯了什么,但它仍然無法正常工作。

您可以在下面看到的代碼:

from threading import Thread
import time
import random

class Creature:

    def __init__(self, name, melee, shielding, health, mana):
        self.name = name
        self.melee = melee
        self.shielding = shielding
        self.health = health
        self.mana = mana

    def attack(self, attacker, opponent, echo):
        while 0 != 1:
            time.sleep(1)
            power = random.randint(1, attacker.melee)
            resistance = random.randint(1, opponent.shielding)
            resultant = power - resistance
            if resistance > 0:
                opponent.health -= resistance
                if opponent.health < 0:
                    msg = opponent.name, " is dead"
                    echo.message(msg)
                    quit()
                else:
                    msg = opponent.name, " lost ", resistance, " hit points due to an attack by ", attacker.name
                    echo.message(msg)

    def healing(self, healed, echo):
        while 0 != 1:
            time.sleep(1)
            if self.mana >= 25:
                if healed.health >= 0:
                    if healed.health < 50:
                        life = random.randint(1, 50)
                        self.mana -= 25
                        healed.health += life
                        if healed.health > 100:
                            healed.health = 100
                        msg = healed.name, " has generated himself and now has ", self.health, " hit points"
                        echo.message(msg)
                else:
                    quit()

class echo:
    def message(self, msg):
        print msg

myEcho = echo()

Monster = Creature("Wasp", 30, 15, 100, 100)
Player = Creature("Knight", 25, 20, 100, 100)

t1 = Thread(target = Player.attack, args = (Monster, Player, myEcho))
t1.start()
t2 = Thread(target = Monster.attack, args = (Player, Monster, myEcho))
t2.start()
t3 = Thread(target=Player.healing(Player, myEcho), args=())
t3.start()
t4 = Thread(target=Monster.healing(Monster, myEcho), args=())
t4.start()

在這里你可以看到混亂的輸出:

*('Wasp'('Knight', ' l, ' lost ', ost 13, ' hit points ', 4, due to an attack by '' hi, 'Waspt poi')nts d
ue to an attack by ', 'Knight')
('Wasp', ' lost ', 12, ' hit points due to an attack by ', 'Knight')
('Knight', ' lost ', 17, ' hit points due to an attack by ', 'Wasp')
('Wasp', ' lost ', 6, ' hit points due to an attack by ', 'Knight'('Knight')
, ' lost ', 1, ' hit points due to an attack by ', 'Wasp')
('Wasp', ' lost ', 5, ' hit points due to an attack by ', 'Knight')
('Knight', ' lost ', 13, ' hit points due to an attack by ', 'Wasp')
(('Wa'Knighsp't', , ' los' lostt ' ', , 32, ' hit points due to an attack by ', 'Knight')
, ' hit points due to an attack by ', 'Wasp')*

你們知道如何解決這個問題嗎?

謝謝!

使用threading.Semaphore來確保不會有任何沖突:

screenlock = Semaphore(value=1)   # You'll need to add this to the import statement.

然后,在調用echo.message之前,插入這一行以獲得輸出權限:

screenlock.acquire()

然后調用echo.message之后的這一行,以便允許另一個線程打印:

screenlock.release()

使用信號量。 一個例子是:

from threading import *
screen_lock = Semaphore(value=1)

現在每次你的進程想要寫一些東西時,它會:

screen_lock.acquire()
print("Something!")
screen_lock.release()

更多關於 semas 的信息在這里(官方文檔)和這里(Laurent Luce 的一篇很棒的文章)。

比信號量稍微好一點的是可重入鎖。

from threading import RLock

class SynchronizedEcho(object):

    print_lock = RLock()

    def __init__(self, global_lock=True):
        if not global_lock:
            self.print_lock = RLock()

    def __call__(self, msg):
        with self.print_lock:
            print(msg)

echo = SynchronizedEcho()   
echo("Test")

重入鎖的好處是它可以與with語句一起使用。 也就是說,如果在使用鎖時拋出任何異常,您可以確保它會在 with 塊的末尾被釋放。 要對信號量執行相同操作,您必須記住編寫 try-finally 塊。

值得注意的是,在訪問和修改 Creatures 的屬性時,您還應該使用信號量或鎖。 這是因為您有多個線程修改屬性值。 所以以同樣的方式,一個打印被另一個打印中斷,輸出是亂碼,所以你的屬性會變成亂碼。

考慮以下:

線程 A

# health starts as 110
if healed.health > 100:
    # Thread A is interrupted and Thread B starts executing
    # health is now 90
    healed.health = 100
    # health is now set to 100 -- ignoring the 20 damage that was done

線程 B

# health is 110 and resistance is 20
opponent.health -= resistance
# health is now 90.
# Thread B is interrupted and Thread A starts executing

使用“日志”模塊而不是打印。 日志記錄是線程安全的,因此每個線程都將按預期完成寫入

在這里你可以找到關於如何使用日志的說明,從本周的python模塊中進行日志記錄

在這里你可以看到它是 從 python doc線程安全的

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM