Lập trình đa luồng trong Python sẽ rất hữu dụng khi chương trình của bạn có nhiều chức năng. VD bạn có thể predict nhiều hình ảnh cùng lúc để tiết kiệm thời gian.
Multithread có công dụng là khai thác tối đa tài nguyên của máy tính để tiết kiệm thời gian. VD như bạn chạy 1 function chưa dùng hết CPU thì gọi nhiều function cùng lúc để khai thác 100% CPU.
Bài này hướng dẫn các bạn cách dễ dàng hơn để tìm hiểu về multi-threading. Thread trong giáo trình CNTT còn gọi là “tiểu trình”.
Lý thuyết
- Một chương trình được gọi là process, khi bạn chạy 1 file *.py tức là bạn đã tạo 1 process
- Trong 1 process bạn có thể tạo nhiều thread, mỗi thread độc lập nhau
- Khi 1 thread chạy xong mặc định nó sẽ kết thúc
- 1 thread chạy 1 function
Bài toán 1: download nhiều files
Bài toán đặt ra là bạn cần download file và lưu vào ổ cứng. Cách thông thường là dùng vòng lặp để download từng file, file này xong thì tới file kia. Nếu có 1 server bị chậm thì tổng thời gian bị kéo dài, do đó download cùng lúc nhiều file sẽ giảm tổng thời gian.
Function Download() có tham số truyền vào là url của file, công việc là download file rồi save vào disk là xong.
Code bên dưới có 3 thread: 1 thread chính và 2 thread để download. Thread download sau khi chạy không quay lại thread chính báo kết quả còn gọi là “fire and forget“.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import urllib.request import os import threading def Download(url, saveDir=None, destFileName=None): if(saveDir == None): saveDir = '.' if(destFileName == None): destFileName = os.path.basename(url) destFileName = os.path.join(saveDir, destFileName) urllib.request.urlretrieve(url, destFileName) url1 = 'https://viscomsolution.com/download/file1.txt' url2 = 'https://viscomsolution.com/download/file2.txt' thread1 = threading.Thread(target=Download, args=(url1,)) thread2 = threading.Thread(target=Download, args=(url2,)) thread1.start() thread2.start() |
Lưu ý khi bạn chỉ truyền 1 tham số vào args thì bạn nên có dấu , để tránh gây ra lỗi.
Bài toán 2: chạy nhiều function và báo kết quả về thread chính
Giả sử bạn có 2 model predict các loài hoa, 2 model này thường cho ra kết quả khác nhau nên cần chạy cả 2. Sau đó so sánh kết quả rồi lấy độ chính xác cao hơn trả về cho user.
Để đơn giản hóa bài toán thì function predict có chứa hàm sleep() để giả lập thời gian chạy.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
import threading import random import time class ThreadWithReturnValue(threading.Thread): def __init__(self, group=None, target=None, name=None, args=(), kwargs={}, Verbose=None): threading.Thread.__init__(self, group, target, name, args, kwargs) self._return = None def run(self): if self._target is not None: self._return = self._target(*self._args, **self._kwargs) def join(self, *args): threading.Thread.join(self, *args) return self._return def PredictByModel1(): sleepSecond = random.randint(0, 5) time.sleep(sleepSecond) percentPredicted = random.randint(0, 100) return percentPredicted def PredictByModel2(): sleepSecond = random.randint(0, 5) time.sleep(sleepSecond) percentPredicted = random.randint(0, 100) return percentPredicted thread1 = ThreadWithReturnValue(target=PredictByModel1) thread2 = ThreadWithReturnValue(target=PredictByModel2) thread1.start() thread2.start() percent1 = thread1.join() percent2 = thread2.join() if(percent1 > percent2): print("Best value is: {0}%".format(percent1)) else: print("Best value is: {0}%".format(percent2)) |
Trong đoạn code trên có class ThreadWithReturnValue, đây là class được viết riêng để dễ dùng. Sau khi start 2 thread thì cần join() lại và lấy kết quả, kết quả nào cao hơn thì lấy và print.
2 hàm predict giống nhau, đều sleep 1 khoảng thời gian và trả về kết quả % ngẫu nhiên. Sau khi join thì 2 thread cũng kết thúc, chỉ còn thread chính chạy và so sánh kết quả.
Tổng kết
Các bạn có thể tải notebook có các đoạn code trên ở link: https://github.com/thigiacmaytinh/TGMTpython/tree/main/multithreading
Hy vọng rằng với 2 example rất đơn giản ở trên các bạn sẽ biết được cách dùng thread. Nếu có gì thắc mắc các bạn có thể hỏi tại forum: https://thigiacmaytinh.com/forum/