Уведомления

Группа в Telegram: @pythonsu

#1 Март 17, 2014 20:00:38

o7412369815963
От:
Зарегистрирован: 2009-06-17
Сообщения: 1986
Репутация: +  32  -
Профиль   Отправить e-mail  

проблема threading

py.user.next
не, я запущу обычную работу со списком
Зачем?

py.user.next
из-за того что он не является потокобезопасным, GIL не даёт писать в него двум потокам сразу
Не в этом дело, из-за GIL в один момент времени работает только один питон код, остальные ждут. (вне зависимости потоко безопасен или нет)

0) Ваш пример
[0.19081257699872367, 0.19112992100417614, 0.19095465500140563]
[0.34615141399990534, 0.4059502980016987, 0.41062400300143054]

1) Одновременный запуск f1+f1 - работает в 2 раза медленней чем f1
111
[0.19041931399988243, 0.19169438000244554, 0.19013405599980615]
[0.47293585800071014, 0.4308473999990383, 0.42105118300241884]
т.е. два “потокобезопасные” lst все равно тормозят - не работают в один момент.

2) f1 запущенный в отдельном потоке работе почти с той же скоростью - с “потокобезопасным” lst
222
[0.19209416800003964, 0.19082266299665207, 0.1915774919980322]
[0.21658378299616743, 0.214570490999904, 0.2036629600042943]

3) а тут вообще работа с lst идет из 3-х потоков, при этом скорость почти не падает.
333
[0.214321926003322, 0.2150491400025203, 0.2151023120022728]
[0.23415685800136998, 0.22996015199896647, 0.22107067499746336]

т.е. пункты 1 и 3 показывают что “не является потокобезопасным” ни причем.
А ваш пример вызывает дополнительный тормоз.

Отредактировано o7412369815963 (Март 17, 2014 20:02:17)

Офлайн

#2 Март 17, 2014 20:17:57

o7412369815963
От:
Зарегистрирован: 2009-06-17
Сообщения: 1986
Репутация: +  32  -
Профиль   Отправить e-mail  

проблема threading

py.user.next
Ваш пример заработал с нормальной скоростью, я просто перекинул кол-во циклов с теста на рабочий цикл,
т.е. тормоз возникает при создании потока и передаче локальной переменной, а без передачи - старт потока не тормозит. Похоже на баг?
У вас какие мысли?

[0.2196149789961055, 0.217363823998312, 0.21051921600155765]
[0.23024766399612417, 0.23042914499819744, 0.22344746100134216]

import timeit
import threading
 
def lf(lst):
    for i in range(1000000):
        lst.append(i)
 
def f1():
    lst = []
    lf(lst)
    lf(lst)
 
def f2():
    lst = []
    lf(lst)
    t = threading.Thread(target=lf, args=(lst,))
    t.start()
    t.join()
 
def main():
    t1 = timeit.Timer('f1()', 'from __main__ import f1')
    t2 = timeit.Timer('f2()', 'from __main__ import f2')
 
    for t in t1, t2:
        print(t.repeat(3, 1))
 
if __name__ == '__main__':
    main()

Офлайн

#3 Март 18, 2014 11:14:02

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10016
Репутация: +  857  -
Профиль   Отправить e-mail  

проблема threading

o7412369815963
Не в этом дело, из-за GIL в один момент времени работает только один питон код, остальные ждут. (вне зависимости потоко безопасен или нет)
просто задайся вопросом, почему GIL вообще существует ?

o7412369815963
py.user.next
не, я запущу обычную работу со списком
Зачем?
ну, чтобы провести вычисления
никогда вычисления с использованием списка не проводил ?

o7412369815963
1) Одновременный запуск f1+f1 - работает в 2 раза медленней чем f1
дожидаться нужно завершения каждого потока
плюс, там ещё основной поток (три потока там)

свой результат:
[guest@localhost threadcmp]$ ./thread_сmp2.py 
[0.3121845519999624, 0.3115454389990191, 0.30946677799875033]
[0.7022323320015857, 0.6940970079995168, 0.6638078140003927]
[guest@localhost threadcmp]$

o7412369815963
т.е. два “потокобезопасные” lst все равно тормозят - не работают в один момент.
а с чего они будут работать, если они не потокобезопасные ?
то, что в них не ведётся одновременная запись, не делает их потокобезопасными
GIL их и блокирует по очереди, чтобы в них сразу два потока не писали (вообще любые два потока)


o7412369815963
2) f1 запущенный в отдельном потоке работе почти с той же скоростью - с “потокобезопасным” lst
это вообще зачем приведено ?
почти с той же скоростью, потому что время уходит на переключения между главным потоком и дочерним и на вызов констуктора класса Thread() и методов .start() и .join()


o7412369815963
3) а тут вообще работа с lst идет из 3-х потоков, при этом скорость почти не падает.
это где там третий ?

o7412369815963
т.е. пункты 1 и 3 показывают что “не является потокобезопасным” ни причем.

вот работа из трёх потоков: главного, первого дочернего и второго дочернего
(добавил одну строку к третьему коду)

#!/usr/bin/env python3
 
import timeit
import threading
 
lst = [] 
def lf():
    del lst[:]
    for i in range(10000):
        lst.append(i)
 
 
def f1():
    lf()
    lf()
 
def f2():
    lf()
    t = threading.Thread(target=lf)
    t.start()
    #t.join()
    t = threading.Thread(target=lf)
    t.start()
    t.join()
 
def main():
    t1 = timeit.Timer('f1()', 'from __main__ import f1')
    t2 = timeit.Timer('f2()', 'from __main__ import f2')
  
    for t in t1, t2:
        print(t.repeat(3, 100))
 
if __name__ == '__main__':
    main()

[guest@localhost threadcmp]$ ./thread_сmp3.py 
[0.3606604479991802, 0.3605620809994434, 0.36211792700123624]
[1.42527558799884, 1.4459451809998427, 1.4245262650001678]
[guest@localhost threadcmp]$

из двух - да, почти та же скорость, а из трёх - в 10 раз медленнее



Отредактировано py.user.next (Март 18, 2014 11:16:48)

Офлайн

#4 Март 18, 2014 11:29:38

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10016
Репутация: +  857  -
Профиль   Отправить e-mail  

проблема threading


o7412369815963
Ваш пример заработал с нормальной скоростью, я просто перекинул кол-во циклов с теста на рабочий цикл,

я немножко скинул с рабочего цикла, и всё вернулось обратно

#!/usr/bin/env python3
 
import timeit
import threading
 
def lf(lst):
    for i in range(1000):
        lst.append(i)
 
def f1():
    lst = []
    lf(lst)
    lf(lst)
 
def f2():
    lst = []
    lf(lst)
    t = threading.Thread(target=lf, args=(lst,))
    t.start()
    t.join()
 
def main():
    t1 = timeit.Timer('f1()', 'from __main__ import f1')
    t2 = timeit.Timer('f2()', 'from __main__ import f2')
 
    for t in t1, t2:
        print(t.repeat(3, 1))
 
if __name__ == '__main__':
    main()

[guest@localhost threadcmp]$ ./thread_сmp5.py 
[0.00031330900128523353, 0.00031356900035461877, 0.0003005090002261568]
[0.0009840080001595197, 0.0008377169997402234, 0.0008744890001253225]
[guest@localhost threadcmp]$



Офлайн

#5 Март 18, 2014 13:11:49

o7412369815963
От:
Зарегистрирован: 2009-06-17
Сообщения: 1986
Репутация: +  32  -
Профиль   Отправить e-mail  

проблема threading

py.user.next
я немножко скинул с рабочего цикла, и всё вернулось обратно
Все правильно, уберите рабочий цикл вообще и получите время запуска потока.
По честному, время запуска потока вообще нужно убрать из замера, мы же меряем разницу работы со списком.
вот тот же тест но без учета старта потока - скорость работы со списком одинаковая во всех потоках:
8.416175842285156e-05
8.153915405273438e-05
8.058547973632812e-05
7.987022399902344e-05

py.user.next
o7412369815963
Не в этом дело, из-за GIL в один момент времени работает только один питон код, остальные ждут. (вне зависимости потоко безопасен или нет)
просто задайся вопросом, почему GIL вообще существует ?
Т.е. вы не согласны с моим утверждением? Я сделал акцент не на GIL, а на термин “потокобезопасный”.

Вот одиночный opcode - потокобезопасен из за GIL, все остальное грубо говоря - нет. Библиотеки локами спасаются.

А вы что имеете ввиду под “не потокобезопасный”, и что вы хотели показать своим тестом с 1 страницы?

Офлайн

#6 Март 19, 2014 08:23:33

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10016
Репутация: +  857  -
Профиль   Отправить e-mail  

проблема threading

o7412369815963
Все правильно, уберите рабочий цикл вообще и получите время запуска потока.
которое в программах никуда не девается
и там не только время запуска, но и время переключения между потоками ещё, потому что потоки не работают одновременно

те, которые не работают, ждут

o7412369815963
и что вы хотели показать своим тестом с 1 страницы?
что оно работает не быстрее, не столько же, а медленнее
то есть, если ты хочешь ускорить работу скрипта за счёт распараллеливания через threading, то оно может сработать в два раза медленнее (чаще не даст прироста по времени, а только усложнит код)

o7412369815963
Я сделал акцент не на GIL, а на термин “потокобезопасный”.
речь-то не про потокобезопасность идёт, а про эффективность threading
типа, стоит ли его применять для ускорения работы скриптов ?

o7412369815963
вот тот же тест но без учета старта потока
этот тест измеряет время работы со списком
а нужно измерять время функции без потоков и функции с потоками (делающих одно и то же)



Офлайн

#7 Март 19, 2014 08:50:07

o7412369815963
От:
Зарегистрирован: 2009-06-17
Сообщения: 1986
Репутация: +  32  -
Профиль   Отправить e-mail  

проблема threading

py.user.next
которое в программах никуда не девается
Ну в правильных программах обычно используют пулы потоков, поэтому во основное время работы программы это особо не влияет.

py.user.next
то есть, если ты хочешь ускорить работу скрипта за счёт распараллеливания через threading, то оно может сработать в два раза медленнее (чаще не даст прироста по времени, а только усложнит код)
Что-б не путать новичков, тут нужно обязательно оговаривать, что это только для питон “команд”, doza_and выше правильно написал:
doza_and
Если вы будете запускать из питона долго работающие скомпилированные модули то получите значительное ускорение от применения threading
А у автора топика - сканер портов - io ожидание, т.е. потоки ему дадут профит, но для конкретного случая лучше использовать асинхронность.
Вы согласны?

Офлайн

#8 Март 19, 2014 09:12:53

o7412369815963
От:
Зарегистрирован: 2009-06-17
Сообщения: 1986
Репутация: +  32  -
Профиль   Отправить e-mail  

проблема threading

Если отвлечься от темы, то я думаю что питон был бы лучше без потоков и GIL, но с корутинами (greenlet),
как stackless python.
Гвидо упоминал, что ему нравится концепция gevent, но пока не знает как реализовать это в питоне (нативно).
Это было бы лучше чем pep3156.

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version