แนวคิดมัลติเธรดดิ้ง
Multithreading เป็นแนวคิดหลักของภาษาโปรแกรมสมัยใหม่เกือบทั้งหมด โดยเฉพาะอย่างยิ่ง python เนื่องจากมีการใช้งานเธรดอย่างง่าย
เธรดคือโปรแกรมย่อยภายในโปรแกรมที่สามารถดำเนินการได้โดยไม่ขึ้นกับส่วนอื่นของโค้ด เธรดดำเนินการในทรัพยากรที่รันได้ของโปรแกรมแบ่งปันบริบทเดียวกัน เช่น หน่วยความจำ
เมื่ออยู่ในกระบวนการเดียว เรากำลังดำเนินการหลายเธรดพร้อมกัน เรียกว่ามัลติเธรด
Python Multithreading Modules สำหรับการใช้งานเธรด
ในการใช้งานเธรดในโปรแกรม python ได้จัดเตรียมโมดูลไว้สองโมดูล -
- เธรด (สำหรับ python 2.x) หรือ _thread (สำหรับ python 3.x) โมดูล
- โมดูลเธรด
ที่โมดูลเธรดสร้างเธรดเป็นฟังก์ชันในขณะที่โมดูลเธรดจัดเตรียมวิธีการเชิงวัตถุเพื่อสร้างเธรด
ไวยากรณ์
_thread.start_new_thread(func, args[, kwargs])
ด้านบนเริ่มต้นเธรดใหม่และส่งคืนตัวระบุ อาร์กิวเมนต์แรกคือฟังก์ชัน func ซึ่งเธรดดำเนินการกับอาร์กิวเมนต์ที่สองที่มีทูเพิลพร้อมรายการอาร์กิวเมนต์ตำแหน่ง อาร์กิวเมนต์ kwargs ที่เป็นตัวเลือกระบุพจนานุกรมของอาร์กิวเมนต์คีย์เวิร์ด เมื่อฟังก์ชันส่งคืน เธรดจะยังคงอยู่
ในที่นี้ เราจะเห็นตัวอย่างพื้นฐานของแอปพลิเคชันไคลเอนต์-เซิร์ฟเวอร์ โดยพื้นฐานแล้วลูกค้าเปิดการเชื่อมต่อซ็อกเก็ตและส่งแบบสอบถามไปยังเซิร์ฟเวอร์ เซิร์ฟเวอร์ตอบกลับ
เมื่อรันโดยไม่มีอาร์กิวเมนต์ โปรแกรมนี้เริ่มต้นด้วยซ็อกเก็ตเซิร์ฟเวอร์ TCP ที่รับฟังการเชื่อมต่อกับ 127.0.0.1 บนพอร์ต 8000
client_thread1.py
import socket import sys def main(): soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) host = "127.0.0.1" port = 8000 try: soc.connect((host, port)) except: print("Connection Error") sys.exit() print("Please enter 'quit' to exit") message = input(" -> ") while message != 'quit': soc.sendall(message.encode("utf8")) if soc.recv(5120).decode("utf8") == "-": pass # null operation message = input(" -> ") soc.send(b'--quit--') if __name__ == "__main__": main()
ในขณะที่โปรแกรมเซิร์ฟเวอร์คือ
server_thread1.py
import socket import sys import traceback from threading import Thread def main(): start_server() def start_server(): host = "127.0.0.1" port = 8000 # arbitrary non-privileged port soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) soc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) print("Socket created") try: soc.bind((host, port)) except: print("Bind failed. Error : " + str(sys.exc_info())) sys.exit() soc.listen(6) # queue up to 6 requests print("Socket now listening") # infinite loop- do not reset for every requests while True: connection, address = soc.accept() ip, port = str(address[0]), str(address[1]) print("Connected with " + ip + ":" + port) try: Thread(target=client_thread, args=(connection, ip, port)).start() except: print("Thread did not start.") traceback.print_exc() soc.close() def clientThread(connection, ip, port, max_buffer_size = 5120): is_active = True while is_active: client_input = receive_input(connection, max_buffer_size) if "--QUIT--" in client_input: print("Client is requesting to quit") connection.close() print("Connection " + ip + ":" + port + " closed") is_active = False else: print("Processed result: {}".format(client_input)) connection.sendall("-".encode("utf8")) def receive_input(connection, max_buffer_size): client_input = connection.recv(max_buffer_size) client_input_size = sys.getsizeof(client_input) if client_input_size > max_buffer_size: print("The input size is greater than expected {}".format(client_input_size)) decoded_input = client_input.decode("utf8").rstrip() result = process_input(decoded_input) return result def process_input(input_str): print("Processing the input received from client") return "Hello " + str(input_str).upper() if __name__ == "__main__": main()
ในการรันสคริปต์ด้านบน ให้รัน server_thread1.py ในเทอร์มินัลเป็น
python server_thread1.py Socket created Socket now listening
เราจะดูหน้าต่างเซิร์ฟเวอร์และทำความเข้าใจโฟลว์ ตอนนี้เปิดเทอร์มินัลไคลเอนต์หลายตัว เรียกใช้เธรดไคลเอนต์
python client_thread1.py Enter 'quit' to exit -> Zack ->
ในเทอร์มินัลอื่น ให้รันโปรแกรมไคลเอ็นต์อื่น &ดูหน้าต่างเทอร์มินัลเซิร์ฟเวอร์ด้วย
python client_thread1.py Enter 'quit' to exit -> Python -> quit
เทอร์มินัลอื่น เรียกใช้เธรดไคลเอ็นต์
python client_thread1.py Enter 'quit' to exit -> world! -> Anothny ->
และเราสามารถเห็นหน้าต่างเซิร์ฟเวอร์ของเราจะแสดงผลลัพธ์บางอย่างเช่น
Socket created Socket now listening Connected with 127.0.0.1:50275 Processing the input received from client Processed result: Hello ZACK Connected with 127.0.0.1:50282 Processing the input received from client Processed result: Hello PYTHON Processing the input received from client Client is requesting to quit Connection 127.0.0.1:50282 closed Connected with 127.0.0.1:50285 Processing the input received from client Processed result: Hello WORLD! Processing the input received from client Processed result: Hello ANOTHNY
ดังนั้น เธรดจึงเป็นเทคนิคทั่วไปวิธีหนึ่งในการจัดการการเชื่อมต่อซ็อกเก็ตและไคลเอนต์หลายตัว