简体   繁体   English

Python - 线程同时打印,弄乱了文本输出

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

I am using 4 threads in an application which return text I would like to print to the user.我在一个应用程序中使用了 4 个线程,这些线程返回我想打印给用户的文本。 Since I would like to avoid the threads to independently print those texts, I have created a class to administrate it...由于我想避免线程独立打印这些文本,因此我创建了一个类来管理它...

I don't know what I am doing wrong here, but it is still not working.我不知道我在这里做错了什么,但它仍然无法正常工作。

The code you can see below:您可以在下面看到的代码:

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()

Here you can see the messed up outputs:在这里你可以看到混乱的输出:

*('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')*

Do you guys have any idea how to fix this issue?你们知道如何解决这个问题吗?

Thanks!谢谢!

Use a threading.Semaphore to ensure that there won't be any conflicts:使用threading.Semaphore来确保不会有任何冲突:

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

Then, before you call echo.message , insert this line in order to acquire the right to output:然后,在调用echo.message之前,插入这一行以获得输出权限:

screenlock.acquire()

and then this line after you call echo.message so as to allow another thread to print:然后调用echo.message之后的这一行,以便允许另一个线程打印:

screenlock.release()

Use a semaphore.使用信号量。 An example would be:一个例子是:

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

Now every time your process wants to write something, it would:现在每次你的进程想要写一些东西时,它会:

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

More about semas here (official documentation) and here (a great article by Laurent Luce).更多关于 semas 的信息在这里(官方文档)和这里(Laurent Luce 的一篇很棒的文章)。

Slightly better than a semaphore is a re-entrant lock.比信号量稍微好一点的是可重入锁。

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")

The benefit of a re-entrant lock is it can be used with a with statement.重入锁的好处是它可以与with语句一起使用。 That is, if any exceptions are thrown whilst using the lock you can be assured it will be released at the end of the with block.也就是说,如果在使用锁时抛出任何异常,您可以确保它会在 with 块的末尾被释放。 To do the same with a semaphore you would have to remember to write a try-finally block.要对信号量执行相同操作,您必须记住编写 try-finally 块。

It's worth noting that you should also be using a semaphore or a lock when accessing and modifying the attributes of your Creatures.值得注意的是,在访问和修改 Creatures 的属性时,您还应该使用信号量或锁。 This is because you have multiple threads modiying the values of the attributes.这是因为您有多个线程修改属性值。 So in the same way one print was interrupted by another print and the output was garbled, so to will your attributes become garbled.所以以同样的方式,一个打印被另一个打印中断,输出是乱码,所以你的属性会变成乱码。

Consider the following:考虑以下:

Thread A线程 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

Thread B线程 B

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

use the 'logging' module instead of print.使用“日志”模块而不是打印。 logging is thread safe, so each thread will finish to write as you expected日志记录是线程安全的,因此每个线程都将按预期完成写入

here you can find explanation how to use logging about logging from python module of the week在这里你可以找到关于如何使用日志的说明,从本周的python模块中进行日志记录

here you can see that it is thread safe from python doc在这里你可以看到它是 从 python doc线程安全的

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM