4

Вопрос по random, python – Сделать случайный модуль поточно-ориентированным в Python

У меня есть приложение, требующее одинаковых результатов при одинаковом случайном числе. Но я считаю, что random.randint не безопасен. Я пробовал мьютекс, но это не работает. Вот мой экспериментальный код (длинный, но простой):

import threading
import random

def child(n, a):
    g_mutex = threading.Lock()
    g_mutex.acquire()
    random.seed(n)
    for i in xrange(100):
        a.append(random.randint(0, 1000))
    g_mutex.release()

def main():
    a = []
    b = []
    c1 = threading.Thread(target = child, args = (10, a))
    c2 = threading.Thread(target = child, args = (20, b))
    c1.start()
    c2.start()
    c1.join()
    c2.join()

    c = []
    d = []
    c1 = threading.Thread(target = child, args = (10, c))
    c2 = threading.Thread(target = child, args = (20, d))
    c1.start()
    c1.join()
    c2.start()
    c2.join()

    print a == c, b == d

if __name__ == "__main__":
    main()

Я хочу написать код для печатиtrue, true, но есть шанс датьfalse, false, Как сделать потокобезопасный рандинт?

  • Error: User Rate Limit Exceeded

    от
  • 16

    Вы можете создавать отдельные экземпляры

    random.Random для каждого потока

    >>> import random
    >>> local_random = random.Random()
    >>> local_random.seed(1234)
    >>> local_random.randint(1,1000)
    967
    

  • 9

    От

    документация дляrandom:

    The functions supplied by this module are actually bound methods of a hidden instance of the random.Random class. You can instantiate your own instances of Random to get generators that don’t share state. This is especially useful for multi-threaded programs, creating a different instance of Random for each thread, and using the jumpahead() method to make it likely that the generated sequences seen by each thread don’t overlap.

    Документация не говорит точно, что это за класс, но показываетclass random.SystemRandom([seed]), а такжеrandom.Random([seed]) кажется, то же самое.

    Пример:

    local_random = random.Random(n)
    for i in xrange(100):
        a.append(local_random.randint(0, 1000))
    

  • 3

    Другие указали на правильный способ использования

    random потокобезопасным способом. Но я чувствую, что важно отметить, что код, который вы написали, не был бы потокобезопасным ни для чего.

    def child(n, a):
        g_mutex = threading.Lock()
        g_mutex.acquire()
        random.seed(n)
        for i in xrange(100):
            a.append(random.randint(0, 1000))
        g_mutex.release()
    

    Каждый поток выполняет этот метод независимо. Это означает, что каждый поток создает свой собственный экземпляр блокировки, получает его, выполняет работу, а затем освобождает его. Если каждый поток не пытается получить одну и ту же блокировку, нет ничего, что могло бы обеспечить непараллельное выполнение. Вам необходимо присвоить одно значениеg_mutex вне контекста вашего метода запуска.

    Edit:

    Я просто хочу добавить, что простое переключение на глобальную блокировку не гарантирует того, что вы точно сказали. Блокировка гарантирует, что только один поток генерирует числа одновременно, но не гарантирует, какой поток будет запущен первым.