LINUX.ORG.RU

Потоки в Python и общие переменные

 ,


0

2

Здравствуйте!

Кто подскажет по потокам в Python?

Задача обработать первый список и получить из него список2. В дальнейшем обрабатываем список2 и выводим результат.

Но второй поток получает список2 с первоначальными данными, а не с обработанными в первом потоке.

Как сделать общую переменную?

игрался с multiprocessing.Manager(), что-то не разобрался.

Списки большие, обрабатывать без нескольких потоков очень долго. Сейчас первая функция работает в цикле и обрабатывает список поштучно, хотелось обработать его в несколько потоков, но появилась проблема.


list2=['1']

pool1 = ThreadPool(3)
    pool1.imap(get_list2, list1, 1)
    pool1.close()
    pool1.join()
print(list2) 
# тут выводит обработанный список

pool2 = ThreadPool(3)
    pool2.imap(obrabotka_list2, list2, 1) # а тут в list2 оказывается снова первоначальный список
    pool2.close()
    pool2.join()



Последнее исправление: constantis (всего исправлений: 1)

Списки большие, обрабатывать без нескольких потоков очень долго

Для ускорения обработки данных используют numpy, он умеет в параллель обрабатывать отдельно от питона («векторные вычисления»)

Но второй поток получает список2 с первоначальными данными, а не с обработанными в первом потоке.

Безотносительно данного случая, архитектура питона такова, что всё равно все эти «потоки» будут обрабатываться в одном треде процессора, поэтому имеет смысл доразобраться с multiprocessing. На numpy это не очень распространяется, так как это табличный процессор, написанный на C, к которому обращается питон.

Опишите более конкретно тип данных, тип обработки, что хотите получить на выходе. Питон в 90% - это «клей» для готовых компонентов, написанных на более быстрых языках. Потому как по вашему вопросу хочется запустить threading с очередью сообщений и семафорами/событиями и т.п., что может добавить отзывчивости программе, но никак не решить вопрос.

Сейчас первая функция работает в цикле и обрабатывает список поштучно

Подозреваю, что numpy вам хватит с головой: https://www.geeksforgeeks.org/how-to-map-a-function-over-numpy-array/

Shadow ★★★★★
()
Последнее исправление: Shadow (всего исправлений: 4)
Ответ на: комментарий от Shadow

Безотносительно данного случая, архитектура питона такова, что всё равно все эти «потоки» будут обрабатываться в одном треде процессора, поэтому имеет смысл доразобраться с multiprocessing.

Там 3.13 и freethreading не за горами.

t184256 ★★★★★
()

в «таких» задачах проще в одном потоке использовать выражения генераторы

т.е при обработке окончательного последовательности запрашивать из выражения - генератора элементы первой последовательности откорректированные

qulinxao3 ★☆
()
Ответ на: комментарий от constantis

Ага, перечитал начальный пост более внимательно. Все-таки, для чего конкретно вам нужны общие переменные? По-хорошему тут нужна только очередь, чтобы складывать в нее промежуточные результаты. Почему не используете multiprocessing.Pool, multiprocessing.Queue?

Zeta_Gundam
()

Pool.imap не будет ничего делать если по нему не проитерироваться. Если элементов не слишком много, то воспользуйся Pool.map. Если много, то:

it = pool1.imap_unordered(get_list2, list1, 1)
for i in it:
    pass

Можно ещё этот итератор в it = tqdm(it, total=len(list1)) обернуть, чтобы было видно прогресс.

ei-grad ★★★★★
()
Последнее исправление: ei-grad (всего исправлений: 2)
Ответ на: комментарий от ei-grad

Ещё можно pool не пересоздавать, раз уж всё равно теперь итерация заканчивается явно.


list2=['1']

with ThreadPool(3) as pool:

    it = pool.imap_unordered(get_list2, list1, 1)
    it = tqdm(it, title="get_list2", total=len(list1))
    for i in it:
        pass

    it = pool.imap_unordered(obrabotka_list2, list2, 1)
    it = tqdm(it, title="obrabotka_list2", total=len(list2))
    for i in it:
        pass
ei-grad ★★★★★
()
Последнее исправление: ei-grad (всего исправлений: 4)

Если на выходе один фиг нужен список, то проще использовать Pool.map и возвращать значение из функции, вместо хардкода внутри этой функции добавления результата в глобальную переменную:

list2 = pool.map(get_list2, list1)
pool.map(obrabotka_list2, list2)

Ещё, chunksize кстати равен 1 по-дефолту, можно указать большее значение чтобы при использовании настоящего multiprocessing.Pool сэкономить на межпроцессной коммуникации. А для ThreadPool наверное пофиг, оно теоретически могло бы lock contention уменьшить, но там один фиг GIL.

ei-grad ★★★★★
()
Последнее исправление: ei-grad (всего исправлений: 2)