Wątkowanie znacznie skraca czas wykonywania programu. Dowiedz się, jak zaimplementować wątki w Pythonie.

Czas wykonania jest jedną z powszechnych miar wydajności programu. Im szybszy czas wykonania, tym lepszy program. Wątkowanie to technika, która umożliwia programowi wykonywanie wielu zadań lub procesów jednocześnie.

Nauczysz się korzystać z wbudowanego języka Python gwintowanie moduł i współbieżne.funkcje moduł. Oba te moduły oferują proste sposoby tworzenia wątków i zarządzania nimi

Znaczenie gwintowania

Wątkowanie skraca czas potrzebny programowi na wykonanie zadania. Jeśli zadanie zawiera wiele niezależnych zadań, można użyć wątków do wykonywania zadań współbieżnie, skracając czas oczekiwania programu na zakończenie jednego zadania przed przejściem do następnego.

Na przykład program, który pobiera wiele plików graficznych z Internetu. Ten program może wykorzystywać wątki do pobierania plików równolegle, a nie pojedynczo. Eliminuje to czas, w którym program musiałby czekać na zakończenie procesu pobierania jednego pliku przed przejściem do następnego.

Program początkowy przed gwintowaniem

Funkcja w poniższym programie reprezentuje zadanie. Zadanie polega na wstrzymaniu wykonywania programu na jedną sekundę. Program wywołuje funkcję dwukrotnie, tworząc w ten sposób dwa zadania. Następnie oblicza czas potrzebny do uruchomienia całego programu, a następnie wyświetla go na ekranie.

import czas

start_time = time.perf_counter()

pokpauza():
wydrukować(„Spanie 1 sekundę…”)
czas spać(1)
wydrukować(„Koniec ze spaniem…”)

pauza()
pauza()
czas_zakończenia = czas.licznik_wyników()
wydrukować(f'Gotowe za {runda (finish_time - start_time, 2)} sekundy)')

Dane wyjściowe pokazują, że wykonanie programu zajęło 2,01 sekundy. Każde zadanie trwało jedną sekundę, a wykonanie reszty kodu zajęło 0,01 sekundy.

Możesz użyć wątków do jednoczesnego wykonywania obu zadań. Wykonanie obu zadań zajmie jedną sekundę.

Implementacja Threading za pomocą modułu Threading

Aby zmodyfikować początkowy kod w celu zaimplementowania wątków, zaimportuj plik gwintowanie moduł. Utwórz dwa wątki, wątek_1 I wątek_2 używając Nitka klasa. Zadzwoń do początek metodę w każdym wątku, aby rozpocząć jej wykonywanie. Zadzwoń do dołączyć metodę w każdym wątku, aby czekała na zakończenie ich wykonania przed wykonaniem reszty programu.

import czas
import gwintowanie
start_time = time.perf_counter()

pokpauza():
wydrukować(„Spanie 1 sekundę…”)
czas spać(1)
wydrukować(„Koniec ze spaniem…”)

wątek_1 = wątek. Wątek (cel=pauza)
wątek_2 = wątek. Wątek (cel=pauza)

wątek_1.start()
wątek_2.start()

wątek_1.dołączenie()
wątek_2.dołączenie()

czas_zakończenia = czas.licznik_wyników()
wydrukować(f'Gotowe za {runda (finish_time - start_time, 2)} sekundy)')

Program uruchomi oba wątki jednocześnie. Skróci to czas potrzebny na wykonanie obu zadań.

Dane wyjściowe pokazują, że czas potrzebny do wykonania tych samych zadań wynosi około sekundy. To połowa czasu, jaki zajął program początkowy.

Implementacja wątkowania przy użyciu modułu concurrent.futures

W Pythonie 3.2 wprowadzono współbieżne.kontrakty terminowe moduł. Ten moduł zapewnia interfejs wysokiego poziomu do wykonywania zadań asynchronicznych przy użyciu wątków. Zapewnia prostszy sposób wykonywania zadań równolegle.

Aby zmodyfikować początkowy program tak, aby korzystał z wątków, zaimportuj moduł concurrent.features. Użyj ThreadPoolExecutor class z modułu concurrent.futures w celu utworzenia puli wątków. Prześlij pauza funkcja do basenu dwa razy. The składać metoda zwraca a przyszły obiekt reprezentujący wynik wywołania funkcji.

Iteruj po kontrakty terminowe i wydrukować ich wyniki za pomocą wynik metoda.

import czas
import współbieżne.kontrakty terminowe

start_time = time.perf_counter()

pokpauza():
wydrukować(„Spanie 1 sekundę…”)
czas spać(1)
powrót„Koniec ze spaniem…”

z współbieżne.kontrakty terminowe. ThreadPoolExecutor() Jak wykonawca:
wyniki = [executor.submit (pauza) Do _ W zakres(2)]
Do F W concurrent.futures.as_completed (wyniki):
drukuj (f.result())

czas_zakończenia = czas.licznik_wyników()

wydrukować(f'Gotowe za {runda (finish_time - start_time, 2)} sekundy)')

Moduł concurrent.features zajmuje się uruchamianiem i łączeniem wątków za Ciebie. Dzięki temu Twój kod jest czystszy.

Wyjście jest identyczne z wyjściem modułu gwintowania. Moduł wątków jest przydatny w prostych przypadkach, w których trzeba uruchomić kilka wątków równolegle. Z drugiej strony moduł concurrent.futures jest przydatny w bardziej złożonych przypadkach, w których trzeba wykonywać wiele zadań jednocześnie.

Korzystanie z wątków w scenariuszu świata rzeczywistego

Użycie wątków do uruchomienia powyższego programu skróciło czas o jedną sekundę. W prawdziwym świecie wątki oszczędzają więcej czasu. Utwórz program, który pobiera obrazy z Internetu. Zacząć od tworzenie nowego środowiska wirtualnego. Uruchom następujące polecenie w terminalu, aby zainstalować upraszanie biblioteka:

żądania instalacji pip

Biblioteka żądań pozwoli Ci wysyłać żądania HTTP. Zaimportuj bibliotekę żądań i bibliotekę czasu.

import upraszanie
import czas

Utwórz listę adresów URL obrazów, które chcesz pobrać. Niech będzie ich co najmniej dziesięć, abyś mógł zauważyć znaczącą różnicę podczas implementacji wątków.

Img_urls = [
' https://images.unsplash.com/photo-1524429656589-6633a470097c',
' https://images.unsplash.com/photo-1530224264768-7ff8c1789d79',
' https://images.unsplash.com/photo-1564135624576-c5c88640f235',
' https://images.unsplash.com/photo-1541698444083-023c97d3f4b6',
' https://images.unsplash.com/photo-1522364723953-452d3431c267',
' https://images.unsplash.com/photo-1513938709626-033611b8cc03',
' https://images.unsplash.com/photo-1507143550189-fed454f93097',
' https://images.unsplash.com/photo-1493976040374-85c8e12f0c0e',
' https://images.unsplash.com/photo-1504198453319-5ce911bafcde',
' https://images.unsplash.com/photo-1530122037265-a5f1f91d3b99',
' https://images.unsplash.com/photo-1516972810927-80185027ca84',
' https://images.unsplash.com/photo-1550439062-609e1531270e',
]

Zapętl listę adresów URL pobierających każdy obraz do tego samego folderu, w którym znajduje się Twój projekt. Wyświetl czas potrzebny do pobrania obrazów, odejmując czas zakończenia od czasu rozpoczęcia.

start_time = time.perf_counter()
Do img_url W img_urls:
img_bytes = request.get (img_url).treść
img_name = img_url.split('/')[3]
nazwa_obrazu = F'{img_name}.jpg'
z otwórz (img_name, 'wb') Jak plik_img:
img_file.write (img_bytes)
wydrukować(F'{img_name} został pobrany...')
czas_zakończenia = czas.licznik_wyników()
wydrukować(f'Gotowe za {finish_time - start_time} sekundy')

Program pobiera około 22 sekund, aby pobrać 12 obrazów. Może się to różnić dla Ciebie, ponieważ czas potrzebny do pobrania obrazów zależy również od szybkości Twojego Internetu.

Zmodyfikuj program, aby używał wątków, używając modułu concurrent.features. Zamiast pętli użyj funkcji. To jest funkcja, którą przekażesz do wykonawca instancja.

import upraszanie
import czas
import współbieżne.kontrakty terminowe

Img_urls = [
' https://images.unsplash.com/photo-1524429656589-6633a470097c',
' https://images.unsplash.com/photo-1530224264768-7ff8c1789d79',
' https://images.unsplash.com/photo-1564135624576-c5c88640f235',
' https://images.unsplash.com/photo-1541698444083-023c97d3f4b6',
' https://images.unsplash.com/photo-1522364723953-452d3431c267',
' https://images.unsplash.com/photo-1513938709626-033611b8cc03',
' https://images.unsplash.com/photo-1507143550189-fed454f93097',
' https://images.unsplash.com/photo-1493976040374-85c8e12f0c0e',
' https://images.unsplash.com/photo-1504198453319-5ce911bafcde',
' https://images.unsplash.com/photo-1530122037265-a5f1f91d3b99',
' https://images.unsplash.com/photo-1516972810927-80185027ca84',
' https://images.unsplash.com/photo-1550439062-609e1531270e',
]

start_time = time.perf_counter()

pokpobierz_obraz(img_url):
img_bytes = request.get (img_url).treść
img_name = img_url.split('/')[3]
nazwa_obrazu = F'{img_name}.jpg'
z otwórz (img_name, 'wb') Jak plik_img:
img_file.write (img_bytes)
wydrukować(F'{img_name} został pobrany...')

z współbieżne.kontrakty terminowe. ThreadPoolExecutor() Jak wykonawca:
executor.map (pobierz_obraz, img_urls)

czas_zakończenia = czas.licznik_wyników()

wydrukować(f'Gotowe za {finish_time-start_time} sekundy')

Po wprowadzeniu gwintowania. Czas znacznie się skraca. Wykonanie programu zajęło tylko 4 sekundy.

Scenariusze odpowiednie dla gwintowania

Niektóre scenariusze odpowiednie dla wątków to:

  • Zadania związane z wejściem/wyjściem: Jeśli program spędza większość czasu na oczekiwaniu na zakończenie operacji wejścia lub wyjścia. Wątkowanie może poprawić wydajność, umożliwiając wykonywanie innych zadań podczas oczekiwania na zakończenie operacji we/wy.
  • Skrobanie sieci: Skrobanie sieci polega na wysyłaniu żądań HTTP i analizowaniu odpowiedzi HTML. Wątkowanie pomaga przyspieszyć proces, umożliwiając jednoczesne wysyłanie wielu żądań.
  • Zadania związane z procesorem: Wątkowanie może pomóc poprawić wydajność, umożliwiając równoległe wykonywanie wielu zadań.

Zapoznaj się z obsługą wątków w innych językach

Python nie jest jedynym językiem obsługującym wątki. Większość języków programowania obsługuje jakąś formę wątków. Warto zapoznać się z implementacją wątków w innych językach. To wyposaża Cię w umiejętności niezbędne do radzenia sobie z różnymi scenariuszami, w których może mieć zastosowanie wątkowanie.