Форум программистов, компьютерный форум, киберфорум
Фаер
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  

Python. Параллельные потоки. Часть 1.

Запись от Фаер размещена 30.09.2012 в 15:34
Показов 33142 Комментарии 14
Метки python, потоки, _thread

Параллельные потоки - вещь полезная и даже интересная, но почувствовать всю их мощь можно, только работая с большими программами и граф. интерфейсами. Большие программы Мы рассматривать не будем, чтобы не забивать голову сторонними предметами, а поэкспериментируем с мелочью. Но сначала немного теории.

GIL(Global Interpreter Lock) - глобальная блокировка интерпретатора. Это понятие не слишком важно для тех, кто не хочет лезть в самую суть параллельных потоков, но кратко ознакомиться с ним всё-же не помешает. На самом деле, большая часть задач, выполняемых компьютером одновременно, не так уж и одновременна. В частности, из-за GIL Мы попадаем в такую ситуацию: в конкретный момент времени интерпретатор выполняет лишь один поток. Параллельность достигается за счёт быстрой смены выполняемых потоков, настолько быстрой (обычно каждые 0.05 сек.), что возникает ощущение одновременности выполнения операций. Таким образом, блокировка не позволяет использовать преимущества многопроцессорных систем, но это недоразумение можно обойти с помощью параллельных процессов, которые Мы разберём через урок.

Модуль _thread
Данный модуль позволяет запускать параллельный поток с помощью функции start_new_thread(). Поток, в Нашем случае, так же представляет собой функцию.

Python
1
2
3
4
5
6
7
8
9
import _thread
from time import sleep
def hel():  #описываем функцию, которую собираемся запустить параллельно основному потоку
    sleep(2)
    print('Hello,world!')
_thread.start_new_thread(hel,()) #запускаем функцию в качестве параллельного потока 
sleep(5)
print('Done')
input()
Вот такой скрипт. Если запустить его, то через две секунды после старта Вы получите надпись Hello,world! и ещё через три(а не через 5, как было бы при вызове функции в этом же потоке) надпись Done.

Обратите внимание, функции start_new_thread() мы передаём два аргумента: непосредственно функцию, которую Мы хотим запустить в параллельном потоке, и кортеж аргументов, которые эта функция принимает. В Нашем случае, передавать какие-либо данные в функцию hel() не нужно.

После вызова start_new_thread() интерпретатор "параллельно" выполняет два потока:
1-ый продолжает выполнять команды, стоящие после start_new_thread()(основной поток).
2-ой выполняет команды, находящиеся в функции hel()(дочерний поток).

Время от времени Нам может требоваться подождать завершения одного из потоков. Как раз для таких случаев в модуле _thread имеются блокировки.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
import _thread
from time import sleep
l=_thread.allocate_lock()#создаём блокировку
def hel():
    sleep(2)
    print('Hello,world!')
    l.acquire()#"замыкаем" блокировку в знак окончания выполнения потока
_thread.start_new_thread(hel,())
while not l.locked():
    pass
sleep(2)
print('Done')
input()
При выполнении этого скрипта происходит следующее:

1. Запускается параллельный поток. Основной поток ждёт пока блокировка l не будет "замкнута"(l.locked()).
2. После окончания выполнения функции hel(), Мы "замыкаем" блокировку с помощью метода acquire().
3. Основной поток получает информацию о том, что параллельный поток был остановлен(l.locked()) и продолжает выполнять команды.

Но это ещё не всё. Выполнение потока можно приостановить, а потом продолжить. Для этого Нам понадобится та же самая блокировка.

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import _thread
from time import sleep
l=_thread.allocate_lock()
def fun():
    while True:
        if not l.locked():
            print('Hello!')
            sleep(1)
def by():
    while True:     
        print('Bye')
        sleep(1)
_thread.start_new_thread(fun,())
sleep(0.5)
_thread.start_new_thread(by,())
sleep(3)
l.acquire()
sleep(3.5)
l.release()
input()
Данный скрипт печатает две надписи поочереди. Через три секунды после запуска он блокирует(l.acquire()) один из потоков(fun()) и продолжает писать только одно слово. Ещё через три секунды выполнение заблокированного потока возобновляется(l.release()) и в консоли снова поочереди появляюся две надписи.

Кроме всего этого, поток можно завершить, передав соответствующую команду в нём же. Грубо говоря, поток завершит сам себя:
Python
1
2
3
4
5
6
7
8
9
10
import _thread
from time import sleep
def hel(): 
    sleep(2)
    _thread.exit()
    print('Hello,world!')
_thread.start_new_thread(hel,()) 
sleep(5)
print('Done')
input()
В данном скрипте функция _thread.exit() завершает поток, в котором выполняется. Таким образом, надпись Hello,world! Вы не увидите, так как поток был прерван до того, как дело дошло до print('Hello,world!').
Метки python, потоки, _thread
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 14
Комментарии
  1. Старый комментарий
    Жаль спасибо нельзя в блоге поставить.
    Запись от bodrich размещена 30.09.2012 в 21:48 bodrich вне форума
  2. Старый комментарий
    Аватар для Фаер
    Цитата Сообщение от bodrich
    Жаль спасибо нельзя в блоге поставить.
    Можно "оценить запись".
    Запись от Фаер размещена 01.10.2012 в 17:51 Фаер вне форума
  3. Старый комментарий
    Аватар для akzo
    Полезная статья)
    Запись от akzo размещена 16.08.2015 в 21:11 akzo вне форума
  4. Старый комментарий
    Аватар для Avazart
    http://habrahabr.ru/post/149420/

    То есть как я понимаю потоки в Python вещь безпонтовая.
    Запись от Avazart размещена 17.08.2015 в 15:13 Avazart вне форума
  5. Старый комментарий
    Аватар для tezaurismosis
    Цитата Сообщение от Фаер
    Это понятие не слишком важно для тех, кто не хочет лезть в самую суть параллельных потоков
    Как раз важно, получается, что потоки совсем и не параллельны. Как вы сами написали, это ощущение параллельности.
    Имхо, это обстоятельство не проходит бесследно для производительности.

    За статью спасибо.
    Запись от tezaurismosis размещена 18.08.2015 в 10:09 tezaurismosis вне форума
  6. Старый комментарий
    Аватар для Фаер
    Цитата Сообщение от Avazart
    То есть как я понимаю потоки в Python вещь безпонтовая.
    Вполне нормальная, если не лепить её, шоб було. К тому же ещё модуль threading есть, если по данной записи мало.
    Запись от Фаер размещена 18.08.2015 в 13:30 Фаер вне форума
  7. Старый комментарий
    Аватар для Avazart
    Ну так что нормального если это по сути псевдопоточность, т.е выигрыша в производительности нет есть только проигрыш?
    Для выигрыша в производительности придется распределять задачи по процессам, а это не одно и тоже что и многопоточность и не всегда приемлемо.
    Запись от Avazart размещена 18.08.2015 в 13:39 Avazart вне форума
  8. Старый комментарий
    Аватар для Фаер
    Цитата Сообщение от Avazart
    Ну так что нормального если это по сути псевдопоточность, т.е выигрыша в производительности нет есть только проигрыш?
    Для выигрыша в производительности придется распределять задачи по процессам, а это не одно и тоже что и многопоточность и не всегда приемлемо.
    Выигрыш потоков состоит в самом механизме, а не в производительности. Вы можете использовать псевдо-параллельность для удобства пользователя(ну, или себя).

    А вот для повышения производительности, да, стоит использовать процессы(из-за GIL. Если его нет, то и потоки распараллелятся), но при этом нужно учитывать, что процесс памяти занимает гораздо больше, управляться с ним сложнее, коммуникации между процессами напряжённы, и переключаются процессы дольше. Так что для распараллеливания(вообще) нужна веская причина, а то они только в минус загонят производительность. И сам механизм, по большому счёту, актуален лишь для многоядерных\многопроцессорных систем.

    Кстати, я как-то раз проводил эксперимент. Чекал список из нескольких миллиардов элементов на Python4Android, у меня получалось, что два потока работают на четверть быстрее, чем один. Три тащили примерно так же, а вот при большем кол-ве время выполнения увеличивалось. Так что производительность(в том числе потоков) - это тоже, такой вопрос, который сильно от ситуации зависит. Нагрузку ещё надо правильно распределять.
    Запись от Фаер размещена 18.08.2015 в 14:08 Фаер вне форума
  9. Старый комментарий
    Аватар для Фаер
    Цитата Сообщение от tezaurismosis
    Как раз важно, получается, что потоки совсем и не параллельны. Как вы сами написали, это ощущение параллельности.
    Ну, в большинстве случаев, это как раз увеличивает скорость работы программы. По сравнению с параллелями. GIL потому и не отменили до сих пор, несмотря на протесты пользователей, что он ускоряет работу.
    Запись от Фаер размещена 18.08.2015 в 14:11 Фаер вне форума
  10. Старый комментарий
    Аватар для Avazart
    Выигрыш потоков состоит в самом механизме, а не в производительности. Вы можете использовать псевдо-параллельность для удобства пользователя(ну, или себя).
    Если нет производительность, то в чем тогда удобство? Тогда уже легче не разделать а делать последовательно, смысл?
    Да если не дает произвоидтельности, то почему это называет потоками?

    коммуникации между процессами напряжённы, и переключаются процессы дольше.
    Именно по этому нужны реальные потоки, а не "механизм" или не понятное "удобство"

    актуален лишь для многоядерных\многопроцессорных систем.
    Мм а у вас стоит комп из каменного века с одним ядром?

    Банальная задача выполнить 5000 HTTP-запросов? Как будете решать?
    Запись от Avazart размещена 19.08.2015 в 00:06 Avazart вне форума
  11. Старый комментарий
    Аватар для akzo
    Цитата Сообщение от Avazart
    Если нет производительность, то в чем тогда удобство?
    Мне эта статья пригодилась когда надо было связать два компа по TCP, нужно было чтоб ввод сообщения и вывод приходящего происходили паралельно(ну или чтобы это так казалось). Без потоков приходилось ждать пока придет сообщение и только потом отправлять свое. Так что в некоторых ситуациях это вполне удобно.
    Запись от akzo размещена 19.08.2015 в 19:07 akzo вне форума
  12. Старый комментарий
    Аватар для Фаер
    Цитата Сообщение от Avazart
    Если нет производительность, то в чем тогда удобство? Тогда уже легче не разделать а делать последовательно, смысл?
    Да уж конечно. После каждой строки кода ставить команду на обновление списка файлов? Или короткую прослушку сокета? Или ещё что-нибудь в этом роде? Так не пойдёт.

    Цитата Сообщение от Avazart
    Именно по этому нужны реальные потоки, а не "механизм" или не понятное "удобство"
    Потоки нужны, когда нужны, а не когда лишь бы влепить, чтобы показать свою опытность.
    akzo, собственно, привёл достойный пример. :like:
    Запись от Фаер размещена 20.08.2015 в 18:53 Фаер вне форума
  13. Старый комментарий
    Аватар для Avazart
    Цитата Сообщение от akzo
    Мне эта статья пригодилась когда надо было связать два компа по TCP, нужно было чтоб ввод сообщения и вывод приходящего происходили паралельно(ну или чтобы это так казалось). Без потоков приходилось ждать пока придет сообщение и только потом отправлять свое. Так что в некоторых ситуациях это вполне удобно.
    И что это был за проект? Хеллоувордный чат?
    Обычно как раз нужно поддерживать последовательность операций при общении запрос-ответ и тогда как раз логично именно ждать ответа...
    Предположу что решение с нормальными потоками было бы куда лучше и эффективнее.

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

    Цитата Сообщение от Фаер
    Потоки нужны, когда нужны, а не когда лишь бы влепить, чтобы показать свою опытность.
    Как раз таки этот костыль в виде псевдо потоков вряд ли куда можно влепить.
    А вот прирост в производительности всегда актуален, а надлежащий средств для этого не предусмотрено в Python.
    Запись от Avazart размещена 20.08.2015 в 23:31 Avazart вне форума
  14. Старый комментарий
    а как сделать так, чтобы оба потока выполнялись в одно и то же время? (мне нужно, чтобы в основном потоке задавался вопрос, а в дочернем шел таймер, и, когда оставалось 0 секунд, программа писала, что ты не успел)
    Запись от Slanix размещена 10.04.2017 в 19:37 Slanix вне форума
 
Новые блоги и статьи
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
Расскажи мне о Мире, бродяга
kumehtar 12.11.2025
— Расскажи мне о Мире, бродяга, Ты же видел моря и метели. Как сменялись короны и стяги, Как эпохи стрелою летели. - Этот мир — это крылья и горы, Снег и пламя, любовь и тревоги, И бескрайние. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru