Уведомления

Группа в Telegram: @pythonsu

#1 Июнь 20, 2013 11:00:04

buddha
От:
Зарегистрирован: 2012-03-02
Сообщения: 422
Репутация: +  15  -
Профиль   Отправить e-mail  

почему разная скорость выполнения аналогичных сценариев с потоками? по книге

Читаю Лутца. В своей книге он пишет примеры работы с модулями _thread, threading.
Вот есть два примера, с одинаковой логикой , но написанных через разные модули.
Так вот на основе модуля threading сценарий выполняется моментально, а на основе модуля _thread около двух секунд. Помогите разобраться почему?
На основе threading:

import threading
 
 
class MyThread(threading.Thread):
 
    def __init__(self, myid, count, mutex):
        self.myid = myid
        self.count = count
        self.mutex = mutex
        threading.Thread.__init__(self)
 
    def run(self):
        for i in range(self.count):
            with self.mutex:
                print('[{}] => {}'.format(self.myid, i))
 
stdoutmutex = threading.Lock()
threads = []
for i in range(10):
    thread = MyThread(i, 100, stdoutmutex)
    thread.start()
    threads.append(thread)
 
for thread in threads:
    thread.join()
print('MAIN EXITING')

На основе _thread:
import _thread
 
 
stdoutmutex = _thread.allocate_lock()
exitmutexes = [_thread.allocate_lock() for i in range(10)]
 
def counter(myId, count):
    for i in range(count):
        stdoutmutex.acquire()
        print('[{}] => {}'.format(myId, i))
        stdoutmutex.release()
    exitmutexes[myId].acquire()
  
for i in range(10):
    _thread.start_new_thread(counter, (i, 100))
 
for mutex in exitmutexes:
    while not mutex.locked(): pass
 
print('main thread exiting')

Отредактировано buddha (Июнь 20, 2013 11:00:38)

Офлайн

#2 Июнь 20, 2013 14:10:26

agalen
От:
Зарегистрирован: 2011-03-23
Сообщения: 185
Репутация: +  17  -
Профиль   Отправить e-mail  

почему разная скорость выполнения аналогичных сценариев с потоками? по книге

Этот цикл очень сильно тормозит работу других потоков:

   while not mutex.locked(): pass

По-хорошему, надо так:
import _thread
print("Start")
stdoutmutex = _thread.allocate_lock()
exitmutexes = [_thread.allocate_lock() for i in range(10)]
def counter(myId, count):
    for i in range(count):
        stdoutmutex.acquire()
        print('[{}] => {}'.format(myId, i))
        stdoutmutex.release()
    exitmutexes[myId].release()  # Not "acquire()" !!!
for i in range(10):
    exitmutexes[i].acquire()
    _thread.start_new_thread(counter, (i, 100))
for mutex in exitmutexes:
    mutex.acquire()
print('main thread exiting')



Офлайн

#3 Июнь 20, 2013 17:06:26

buddha
От:
Зарегистрирован: 2012-03-02
Сообщения: 422
Репутация: +  15  -
Профиль   Отправить e-mail  

почему разная скорость выполнения аналогичных сценариев с потоками? по книге

Так, в твоей реализации добавился цикл, для вызова метода acquire() у объекта блокировки. И заменен вызов метода того же объекта блокировки в функции counter.

Для чего и почему так?
Я пока мало знаю работу с потоками, у тебя получается, что потоки уже выполняются и вызывают метод exitmutexes.release() до вызова метода mutex.acquire(). Это нормально? Что это значит в общем?(буду рад простому объяснению на бананах)

Вот что сказано в документации:

lock.release() 
Releases the lock. The lock must have been acquired earlier, but not necessarily by the same thread.

Офлайн

#4 Июнь 21, 2013 08:43:30

agalen
От:
Зарегистрирован: 2011-03-23
Сообщения: 185
Репутация: +  17  -
Профиль   Отправить e-mail  

почему разная скорость выполнения аналогичных сценариев с потоками? по книге

acquire вызывается ещё до старта потока из главного треда (строка перед start_new_thread).
Основная причина такой замены - у мутекса вызов acquire реализован с “правильным” ожиданием.
Вообще, конечно, использование мутексов для ожидания завершения потоков - не самый првильный метод, но у модуль _thread не дает большего выбора.
Если посмотреть реализацию, то threading активно использует _thread. А threading.Lock вообще тот-же объект, что и _thread.allocate_lock.



Офлайн

#5 Июнь 21, 2013 13:30:08

buddha
От:
Зарегистрирован: 2012-03-02
Сообщения: 422
Репутация: +  15  -
Профиль   Отправить e-mail  

почему разная скорость выполнения аналогичных сценариев с потоками? по книге

А чтобы это всё прокурить , куда лучше смотреть, что копать, что читать? наверно вообще от питона отойти надо?(я про то, чтобы понять как правильно)

А то вот читаю щас про потоки, GIL. Пока у меня такая мысль, что эффективно на питоне использовать ветвление процессов. А вот смысла в питоновских потоках вообще никакого!

Офлайн

#6 Июнь 21, 2013 14:42:15

agalen
От:
Зарегистрирован: 2011-03-23
Сообщения: 185
Репутация: +  17  -
Профиль   Отправить e-mail  

почему разная скорость выполнения аналогичных сценариев с потоками? по книге

Потоки нужны для работы с файлами, сетью, базами данных и т.д.
Вычисления на чистом питоне они не ускоряют из-за GIL. Для таких задач используют multiprocessing, numpy или пишут модули на C.
На этом форуме это уже много раз обсуждалось.



Офлайн

#7 Июнь 21, 2013 14:45:01

buddha
От:
Зарегистрирован: 2012-03-02
Сообщения: 422
Репутация: +  15  -
Профиль   Отправить e-mail  

почему разная скорость выполнения аналогичных сценариев с потоками? по книге

Да много где это обсуждалось) да и по форуму я искал, обсуждают те, кто уже работал с потоками. Для тех , кто въезжает в потоки, мало информации простой…

Офлайн

#8 Июнь 21, 2013 14:51:23

buddha
От:
Зарегистрирован: 2012-03-02
Сообщения: 422
Репутация: +  15  -
Профиль   Отправить e-mail  

почему разная скорость выполнения аналогичных сценариев с потоками? по книге

agalen
Потоки нужны для работы с файлами, сетью, базами данных и т.д.

А если конкретно с копированием файлов с сетевого диска на локальный? Где то читал, что тут потоки не имеют значения, из-за того что жёсткий диск один и пишет там одна головка на диске, которая просто переключается, если поток другой…

Офлайн

Board footer

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

Powered by DjangoBB

Lo-Fi Version