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

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

Запись от Фаер размещена 30.09.2012 в 15:34
Показов 33462 Комментарии 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 вне форума
 
Новые блоги и статьи
Гайд, как ворваться в вайб-кодинг в мае 2026
Noname2331 17.05.2026
Простите за получившееся полотно текста, я даже не знаю, как его разбить на главы. Тут, что называется, ни добавить ни убавить, одна сцена одним дублем. На моих глазах недавно случилось чудо. Как. . .
[golang] Алгоритм «Хак Госпера»
alhaos 17.05.2026
Алгоритм «Хак Госпера» Хак Госпера (Gosper's Hack) — алгоритм нахождения следующего по величине числа с тем же количеством установленных бит. Придуман Биллом Госпером в 1970-х, опубликован в. . .
Рисование бинарного древа до 6-го колена на js, svg.
russiannick 17.05.2026
<svg width="335" height="240" viewBox="0 0 335 240" fill="#e5e1bb"> <style> <!]> </ style> <g id="bush"> </ g> </ svg> function fn(){ let rost;/ / высота древа let xx=165,yy=210,w=256;
FSharp: interface of module
DevAlt 16.05.2026
Интерфейс модуля F# позволяет управлять доступностью членов, содержащихся в реализации модуля. По-умолчанию все члены модуля доступны: module Foo let x = 10 let boo () = printfn "boo" . . .
Хитросплетение родственных связей пантеона греческих богов.
russiannick 14.05.2026
Однооконник, позволяющий узреть и изучить отдельных героев древней Греции. <!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible". . .
[golang] Угол между стрелками часов
alhaos 12.05.2026
По заданным значениям часа и минуты необходимо определить значение меньшего угла между стрелками аналогового циферблата часов. import "math" func angleClock(hour int, minutes int) float64 { . . .
Debian 13: Установка Lazarus QT5
ВитГо 09.05.2026
Эта инструкция моя компиляция инструкций volvo https:/ / www. cyberforum. ru/ blogs/ 203668/ 10753. html и его же старой инструкции по установке Lazarus с gtk2. . .
Нейросеть на алгоритме "эстафета хвоста" как перспектива.
Hrethgir 06.05.2026
На десерт, когда запущу сервер. Статья тут https:/ / habr. com/ ru/ articles/ 1030914/ . Автор я сам, нейросеть только помогает в вопросах которые мне не известны - не знаю людей которые знали-бы. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru