Форум сайта python.su
15
Читаю Лутца. В своей книге он пишет примеры работы с модулями _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')
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)
Офлайн
17
Этот цикл очень сильно тормозит работу других потоков:
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')
Офлайн
15
Так, в твоей реализации добавился цикл, для вызова метода 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.
Офлайн
17
acquire вызывается ещё до старта потока из главного треда (строка перед start_new_thread).
Основная причина такой замены - у мутекса вызов acquire реализован с “правильным” ожиданием.
Вообще, конечно, использование мутексов для ожидания завершения потоков - не самый првильный метод, но у модуль _thread не дает большего выбора.
Если посмотреть реализацию, то threading активно использует _thread. А threading.Lock вообще тот-же объект, что и _thread.allocate_lock.
Офлайн
15
А чтобы это всё прокурить , куда лучше смотреть, что копать, что читать? наверно вообще от питона отойти надо?(я про то, чтобы понять как правильно)
А то вот читаю щас про потоки, GIL. Пока у меня такая мысль, что эффективно на питоне использовать ветвление процессов. А вот смысла в питоновских потоках вообще никакого!
Офлайн
17
Потоки нужны для работы с файлами, сетью, базами данных и т.д.
Вычисления на чистом питоне они не ускоряют из-за GIL. Для таких задач используют multiprocessing, numpy или пишут модули на C.
На этом форуме это уже много раз обсуждалось.
Офлайн
15
Да много где это обсуждалось) да и по форуму я искал, обсуждают те, кто уже работал с потоками. Для тех , кто въезжает в потоки, мало информации простой…
Офлайн
15
agalen
Потоки нужны для работы с файлами, сетью, базами данных и т.д.
Офлайн