Переменная передается нескольким потокам одной и той же функции - PullRequest
1 голос
/ 09 октября 2019

В настоящее время я работаю над системой, которая отправляет webhooks на несколько Discord с использованием dhooks.

Эта функция используется для вызова функции, которая отправляет webhooks. Длина webhooks равна 2, и это список списков.

for hook in webhooks:
    thread.start_new_thread(send_hook,(hook, embed, tag))

Это функция send_hook:

def send_hook(hook, embed, tag):

    embed.set_footer(text="{} x Will".format(hook[0])) <-- This is the part where the error happens

    webhook = Webhook(hook[1])
    webhook.send(embed=embed)

Я получаю ошибку, когда я устанавливаюнижний колонтитул в строке 2 send_hook, переменная, вставленная в переменную embed, иногда отправляется не тем веб-зацепкам - почти как если бы она была перегружена.

Как пример:

Это мой список webhooks: [["Webhook 1 text", "discordwebhook1"], ["Webhook 2 text", "discordwebhook1"]].

Что произойдет, так это то, что в канале discordwebhook1 нижний колонтитул скажет «текст Webhook 1», но в канале discordwebhoo2 нижний колонтитул также скажет «текст Webhook 1».

Я попытался создать новую переменную встраивания в функции send_hook - однако это также не сработало (код ниже).

def send_hook(hook, embed, tag):
    new_embed = embed
    new_embed.set_footer(text="{} x Will".format(hook[0])) <-- This is the part where the error happens

    webhook = Webhook(hook[1])
    webhook.send(embed=new_embed)

Я ценю любую помощь!

Спасибо

Ответы [ 2 ]

1 голос
/ 09 октября 2019

как вы получаете "вставлять"? обратите внимание, что 'embed' и 'tag' всегда передаются каждому вновь созданному потоку ... вам нужно сделать глубокую копию каждого при необходимости

from copy import deecopy

for hook in webhooks:
    thread.start_new_thread(send_hook,(hook, deepcopy(embed), tag))
0 голосов
/ 09 октября 2019

Вы испытываете состояние гонки . Два потока имеют доступ к одной и той же переменной, и они оба изменяют переменную. Результат вашей программы зависит от того, какой из них достигнет кода, который первым изменяет переменную.

Существует два возможных решения в зависимости от того, как вы хотите решить проблему:

  1. Если вам не нужно, чтобы все потоки разделяли одно и то же значение , или если объект небольшой и дешевый для копирования, сделайте копию передаваемой переменной, прежде чем передать ее, передавdeepcopy(embed) вместо embed - см. решение, отправленное @ user1438644 для кода.

  2. Если вы хотите, чтобы все потоки имели одинаковое значение, или если копирование объекта стоит дорого, вам нужно будет создать блокировку с помощью my_lock = threading.Lock(), и когда вы доберетесь до состояния гонки в вашей программе (то есть, части, которая изменяет переменную общего доступа)), окружите его диспетчером контекста with my_lock:, который получает блокировку при запуске и возвращает блокировку по окончании. Например:

import threading
my_lock = threading.Lock()

# your code here

for hook in webhooks:
    threading.Thread(send_hook, args=(hook, embed, tag))

# more code here

def send_hook(hook, embed, tag):
    # Ensure embed is only changed by one thread at a time
    with my_lock:
        print("Lock acquired")
        embed.set_footer(text="hello world")
        webhook = Webhook(hook[1])
        webhook.send(embed=embed)
...