Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30

Можно ли ждать завершения одновременно сразу нескольких потоков?

29.01.2017, 00:05. Показов 3142. Ответов 16
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Можно ли ждать завершения одновременно сразу нескольких потоков или выставления нескольких эвентов ?
Нечто вроде аналога WaitForMultiplyObjects().

В псевдокоде нечто вроде:
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import threading
import time
 
def thread_function(i):
    time.sleep(i)
 
def main():
    threads = []
    for i in range(2):
        thread = threading.Thread(target=thread_function, args=(i))
        threads.append(thread)
 
    index_of_thread = wait_one_of_threads(threads) #  и wait_all_threads(threads)
 
    print(index_of_thread, "finished first...")
 
if __name__ == '__main__':
    main()
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
29.01.2017, 00:05
Ответы с готовыми решениями:

Правильно создать пул потоков, запустить эти потоки одновременно и дождаться их завершения
Добрый день! Подскажите пожалуйста, как правильно создать пул потоков, запустить эти потоки одновременно и дождаться завершения всех...

Как дождаться завершения нескольких потоков
Добрый день. Столкнулся с такой проблемой: в методе main() создается n одинаковых потоков, каждый из которых обрабатывает по файлу......

Запуск нескольких независимых потоков. Дождаться завершения всех (C++ 11)
Доброго времени суток. Подскажите, как запустить несколько независимых потоков, но дождаться, пока все завершатся? В каждом потоке есть...

16
2742 / 2341 / 620
Регистрация: 19.03.2012
Сообщений: 8,830
29.01.2017, 00:08
Python
1
2
for i in threads:
    i.join()
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
29.01.2017, 00:12  [ТС]
Цитата Сообщение от alex925 Посмотреть сообщение
Python
1
2
for i in threads:
    i.join()
Это совсем не то.

Мне нужно знать завершился ли один из потоков и какой именно...
(И естественно без бесконечных циклов пожирающих ресурсы)

Тоже самый вопрос возникает насчет объектов-событий и процессов.
0
2742 / 2341 / 620
Регистрация: 19.03.2012
Сообщений: 8,830
29.01.2017, 00:27
Avazart, нужно на голом Python? Если использовать pyqt, то достаточно просто сделать.

Или можно использовать очереди. Каждый поток перед завершением пусть что нибудь кидает в очередь, а в главном потоке вызоваем метод get, который будет ждать, пока в очереди появиться хоть что-то.
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
29.01.2017, 00:29  [ТС]
Я нашел решение для потоков, через очередь.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import threading
import queue
import random
import time
 
 
def thread_function(i, q):
    time.sleep(random.randint(1, 5))
    q.put(i)
 
 
def main():
    q = queue.Queue()
    threads = []
    for i in range(2):
        thread = threading.Thread(target=thread_function, args=(i, q))
        threads.append(thread)
        thread.start()
 
    counter = 2
    while counter:
        i = q.get()
        print("#{} finished.".format(i))
        counter -= 1
 
    print("Done!")
 
 
if __name__ == '__main__':
    main()
Теперь вопросы:
  1. Можно ли сделать лучше/проще?
  2. Можно ли сделать подобное для процессов и событий?
0
2742 / 2341 / 620
Регистрация: 19.03.2012
Сообщений: 8,830
29.01.2017, 00:29
2. Для процессов можно сделать
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
29.01.2017, 16:30  [ТС]
Задумка вот в чем:
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import multiprocessing
import threading
import random
import time
 
def process_function(i, q):
    time.sleep(random.randint(1, 5))
    q.put(i)
 
 
def thread_function(n):
    q = multiprocessing.Queue()
    for i in range(n):
        process = multiprocessing.Process(target=process_function, args=(i, q))
        process.start()
 
    counter = n
    while counter:
        i = q.get()
        print("#{} finished.".format(i))
        counter -= 1
        # Послать сигнал с результатом в основной поток Qt эвент лупу !!!
 
def main():
    thread = threading.Thread(target=thread_function,args=(5,))
    thread.start()
    thread.join()
    print("Done!")
 
if __name__ == '__main__':
    main()

Т.е что бы решить проблему Реализация и использование потоков в PyQt

Добавлено через 15 часов 50 минут
Все бы хорошо, но если заменить на ProcessPoolExecutor процессы виснут намертво.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from concurrent.futures import ProcessPoolExecutor
import multiprocessing
import threading
import random
import time
from datetime import datetime
 
 
def process_function(i, q):
    time.sleep(random.randint(5, 20))
    q.put(i)
 
 
def thread_function(n):
    manager = multiprocessing.Manager()
    q = manager.Queue()
    # for i in range(n):
    #     process = multiprocessing.Process(target=process_function, args=(i, q))
    #     process.start()
 
    with ProcessPoolExecutor(max_workers=2) as executor:
        for i in range(n):
            executor.submit(process_function, i)
 
    counter = n
    while counter:
        i = q.get()
        print("{1} #{0} finished.".format(i, datetime.now().strftime('%H:%M:%S')))
        counter -= 1
    print("Done!")
 
 
def main():
    thread = threading.Thread(target=thread_function, args=(5,))
    thread.start()
    thread.join()
 
 
if __name__ == '__main__':
    main()
0
29.01.2017, 17:28
 Комментарий модератора 
Avazart, называйте темы по-нормальному, а не набором ключевых слов.
0
757 / 306 / 190
Регистрация: 20.05.2016
Сообщений: 593
29.01.2017, 18:15
Вы, кажется, q забыли передать
Python
1
executor.submit(process_function, i, q)
Так процессы завершаются, но почему-то, на randint не взирая, совершенно синхронно

Как приблизительный вариант (если уж PoolExecutor)

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from concurrent.futures import ProcessPoolExecutor
import multiprocessing
import threading
import random
import time
from datetime import datetime
 
 
def process_function(i):
    start = datetime.now().strftime('%H:%M:%S')
    t = random.randint(5, 20)
    time.sleep(t)
    return i, start, t
 
 
def thread_function(n):
  
    def fn(fs):
        i, start, delay = fs.result()
        print("{1} #{0} finished. Result {2}: start - {3}, delay - {4}".format(fs, datetime.now().strftime('%H:%M:%S'), i, start, delay))
 
    with ProcessPoolExecutor(max_workers=2) as executor:
        for i in range(n):
            e = executor.submit(process_function, i)
            
            e.add_done_callback(fn)
    
 
def main():
    thread = threading.Thread(target=thread_function, args=(5,))
    thread.start()
    thread.join()
 
 
if __name__ == '__main__':
    main()
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
29.01.2017, 19:51  [ТС]
Цитата Сообщение от shsv Посмотреть сообщение
Вы, кажется, q забыли передать
Не меняет ситуации, опечатка.

Цитата Сообщение от shsv Посмотреть сообщение
Так процессы завершаются, но почему-то, на randint не взирая, совершенно синхронно
Там в пуле два процесса, учли?

Через колбек я тоже уже догадался, но обнаружил интересную вещь:
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import os
from concurrent.futures import ProcessPoolExecutor
import multiprocessing
import threading
import random
import time
from datetime import datetime
 
 
def process_function(i):
    delay = random.randint(5, 20)
    print("thread th id: {0}, pid: {1} value: {2} time: {3} delay: {4}"
          .format(threading.get_ident(), os.getppid(),
                  i,
                  datetime.now().strftime('%H:%M:%S'),
                  delay))
    time.sleep(delay)
    return i ** 2
 
def done_callback(future):
    print("callback th id: {0}, pid: {1} result: {2} time: {3}"
          .format(threading.get_ident(), os.getppid(),
                   future.result(), datetime.now().strftime('%H:%M:%S')))
 
 
def thread_function(n):
    print("creator th id: {0}, pid: {1}".format(threading.get_ident(), os.getppid()))
    with ProcessPoolExecutor(max_workers=2) as executor:
        for i in range(n):
            future = executor.submit(process_function, i)
            future.add_done_callback(done_callback)
 
 
def main():
    print("main th id: {0}, pid: {1}".format(threading.get_ident(),os.getppid()))
    thread = threading.Thread(target=thread_function, args=(5,))
    thread.start()
    thread.join()
 
 
if __name__ == '__main__':
    main()
Колбеки иногда вызывается совсем с левого потока, т.е это и не основной поток и не создающий процессы.
А иногда колбеки все же вызываются из создающего потока.

Добавлено через 4 минуты
У меня выводит примерно следующее:
main th id: 2648, pid: 4536
creator th id: 4048, pid: 4536
thread th id: 2108, pid: 5328 value: 0 time: 17:35:56 delay: 12
thread th id: 3020, pid: 5328 value: 1 time: 17:35:56 delay: 16
callback th id: 2552, pid: 4536 result: 0 time: 17:36:08
thread th id: 2108, pid: 5328 value: 2 time: 17:36:08 delay: 6
callback th id: 2552, pid: 4536 result: 1 time: 17:36:12
thread th id: 3020, pid: 5328 value: 3 time: 17:36:12 delay: 9
callback th id: 2552, pid: 4536 result: 4 time: 17:36:14
thread th id: 2108, pid: 5328 value: 4 time: 17:36:14 delay: 17
callback th id: 2552, pid: 4536 result: 9 time: 17:36:21
callback th id: 2552, pid: 4536 result: 16 time: 17:36:31
Добавлено через 36 минут
Вообще какая то непонятная ерунда, я изменил max_workers=5 т.е по сути на каждую задачу должно быть по одному процессу, но выдает что все задачи находятся в одном процессе:

main th_id: 4060, pid: 4536
creator th_id: 984, pid: 4536

thread th_id: 6104, pid: 1400 value: 0 time: 18:06:14 delay: 11
thread th_id: 1952, pid: 1400 value: 1 time: 18:06:14 delay: 8
thread th_id: 1372, pid: 1400 value: 2 time: 18:06:14 delay: 13
thread th_id: 5508, pid: 1400 value: 3 time: 18:06:14 delay: 11
thread th_id: 196, pid: 1400 value: 4 time: 18:06:14 delay: 17

callback th_id: 2080, pid: 4536 result: 1 time: 18:06:22
callback th_id: 2080, pid: 4536 result: 0 time: 18:06:25
callback th_id: 2080, pid: 4536 result: 3 time: 18:06:25
callback th_id: 2080, pid: 4536 result: 2 time: 18:06:27
callback th_id: 2080, pid: 4536 result: 4 time: 18:06:31
Это os.getppid() врёт?

Добавлено через 41 минуту
Судя по диспетчеру задач действительно создается 5 процессов, но заметно что в одном из этих процессов а именно у того чей pid выводит создается ~5...7 потоков, в остальных процессах ~2...4 потока.

Т.е. как работает и можно ли назвать это нормальной работой ProcessPoolExecutor вообще ничего нельзя сказать.
0
757 / 306 / 190
Регистрация: 20.05.2016
Сообщений: 593
29.01.2017, 19:53
os.getppid() - родительский процесс, так что, вроде, верно всё. А с потоком да, не понятно. Там в реализации создается поток, который
Manages the communication between this process and the worker processes.
должно быть из него колбэки и вызываются, но я не разобрался пока

У меня в процессах по одному потоку, кроме родительского, там их 4 ~ 5
1
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
29.01.2017, 20:09  [ТС]
Цитата Сообщение от shsv Посмотреть сообщение
os.getppid() - родительский процесс, так что, вроде, верно всё.
Да заменил на

Python
1
2
from win32process import GetCurrentProcessId
GetCurrentProcessId()
Все верное показывает теперь.
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
29.01.2017, 20:13  [ТС]
Выглядит так:
Кликните здесь для просмотра всего текста
0
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
29.01.2017, 20:20  [ТС]
Цитата Сообщение от shsv Посмотреть сообщение
должно быть из него колбэки и вызываются, но я не разобрался пока
В приципе, в моем случае думаю это не важно, я собираюсь вызывать из него слот виджета Qt потокобезопасным способом.
0
757 / 306 / 190
Регистрация: 20.05.2016
Сообщений: 593
29.01.2017, 20:41
Цитата Сообщение от shsv Посмотреть сообщение
должно быть из него колбэки и вызываются, но я не разобрался пока
Нельзя сказать, что всё кристально ясно, но да, точно, колбеки вызываются из него

Добавлено через 3 минуты
(Текущий процесс - os.getpid(), разница в одной p)
1
Эксперт С++
 Аватар для Avazart
8488 / 6155 / 615
Регистрация: 10.12.2010
Сообщений: 28,683
Записей в блоге: 30
29.01.2017, 21:27  [ТС]
Оказывается есть такая штука которую я искал concurrent.futures.wait c флагами:

Python
1
 concurrent.futures.wait(fs, timeout=None, return_when=ALL_COMPLETED)
FIRST_COMPLETED The function will return when any future finishes or is cancelled.
FIRST_EXCEPTION The function will return when any future finishes by raising an exception. If no future raises an exception then it is equivalent to ALL_COMPLETED.
ALL_COMPLETED The function will return when all futures finish or are cancelled.

Можно было её использовать...

Добавлено через 6 минут

Не по теме:

Касательно использование этого для использования совместно с Qt интерфейсом Реализация и использование потоков в PyQt

1
757 / 306 / 190
Регистрация: 20.05.2016
Сообщений: 593
29.01.2017, 22:21
Чтобы как-то подытожить с потоками
В моём случае в главном (родительском, том что обозначен как main) процессе 4 потока:
1. Главный поток - main,
2. Поток, явно нами созданный - creator,
3. Поток, созданный реализацией ProcessPoolExecutor, для обеспечения взаимодействия между главным и, создаваемыми PoolExecutor'ом, рабочими процессами (из него, в частности, вызываются колбеки),
4. Наконец, последний, создан реализацией multiprocessing.Queue. Queue используется внутри ProcessPoolExecutor'а для складирования результатов работы дочерних процессов.

В дочерних процессах по одному потоку.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
29.01.2017, 22:21
Помогаю со студенческими работами здесь

Запуск одновременно нескольких потоков
Вот как запустить например сразу 20 потоков ? что бы работа, например http запроса или еще что-то выполнялась быстрее. Запуск одного...

Запуск нескольких потоков одновременно
Здравствуйте. Подскажите пожалуйста как запустить несколько потоков в такой ситуации. Есть некий путь к папке, необходимо по этому пути...

Запуск нескольких потоков одновременно
Здравствуйте. У меня есть стэк объектов, с которыми нужно произвести какие-то действия. Причем работать нужно в трех потоках. То...

Корректная работа нескольких потоков одновременно
Дорогие пользователи возникла проблема... Мне нужно запустить програму-чекер в многопотоке... Но как там много идёт время выполнения...

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


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
Опции темы

Новые блоги и статьи
SDL3 для Web (WebAssembly): Работа со звуком через SDL3_mixer
8Observer8 08.02.2026
Содержание блога Пошагово создадим проект для загрузки звукового файла и воспроизведения звука с помощью библиотеки SDL3_mixer. Звук будет воспроизводиться по клику мышки по холсту на Desktop и по. . .
SDL3 для Web (WebAssembly): Основы отладки веб-приложений на SDL3 по USB и Wi-Fi, запущенных в браузере мобильных устройств
8Observer8 07.02.2026
Содержание блога Браузер Chrome имеет средства для отладки мобильных веб-приложений по USB. В этой пошаговой инструкции ограничимся работой с консолью. Вывод в консоль - это часть процесса. . .
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru