Найти - Пользователи
Полная версия: почему разная скорость выполнения аналогичных сценариев с потоками? по книге
Начало » Python для новичков » почему разная скорость выполнения аналогичных сценариев с потоками? по книге
1
buddha
Читаю Лутца. В своей книге он пишет примеры работы с модулями _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')
agalen
Этот цикл очень сильно тормозит работу других потоков:
   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')
buddha
Так, в твоей реализации добавился цикл, для вызова метода 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.
agalen
acquire вызывается ещё до старта потока из главного треда (строка перед start_new_thread).
Основная причина такой замены - у мутекса вызов acquire реализован с “правильным” ожиданием.
Вообще, конечно, использование мутексов для ожидания завершения потоков - не самый првильный метод, но у модуль _thread не дает большего выбора.
Если посмотреть реализацию, то threading активно использует _thread. А threading.Lock вообще тот-же объект, что и _thread.allocate_lock.
buddha
А чтобы это всё прокурить , куда лучше смотреть, что копать, что читать? наверно вообще от питона отойти надо?(я про то, чтобы понять как правильно)

А то вот читаю щас про потоки, GIL. Пока у меня такая мысль, что эффективно на питоне использовать ветвление процессов. А вот смысла в питоновских потоках вообще никакого!
agalen
Потоки нужны для работы с файлами, сетью, базами данных и т.д.
Вычисления на чистом питоне они не ускоряют из-за GIL. Для таких задач используют multiprocessing, numpy или пишут модули на C.
На этом форуме это уже много раз обсуждалось.
buddha
Да много где это обсуждалось) да и по форуму я искал, обсуждают те, кто уже работал с потоками. Для тех , кто въезжает в потоки, мало информации простой…
buddha
agalen
Потоки нужны для работы с файлами, сетью, базами данных и т.д.

А если конкретно с копированием файлов с сетевого диска на локальный? Где то читал, что тут потоки не имеют значения, из-за того что жёсткий диск один и пишет там одна головка на диске, которая просто переключается, если поток другой…
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB