วิธีจัดการทรัพยากรใน Python ด้วย Context Managers
สิ่งสำคัญคือต้องจัดการทรัพยากรอย่างเหมาะสมเมื่อสร้างแอปพลิเคชันเพื่อป้องกันหน่วยความจำรั่ว รับประกันการล้างข้อมูลที่เหมาะสม และรักษาเสถียรภาพของแอปพลิเคชันของคุณ ผู้จัดการบริบทนำเสนอโซลูชันที่ปรับปรุงแล้วสำหรับสถานการณ์นี้ ผู้จัดการบริบทปรับปรุงการจัดการทรัพยากรให้มีประสิทธิภาพโดยทำให้กระบวนการได้มาและเผยแพร่ทรัพยากรเป็นไปโดยอัตโนมัติ
ผู้จัดการบริบทคืออะไร?
ผู้จัดการบริบทโดยพื้นฐานแล้วคืออ็อบเจ็กต์ที่อธิบายกลยุทธ์ในการรักษาความปลอดภัยทรัพยากรและเผยแพร่เมื่อไม่ต้องการอีกต่อไป เอนทิตีเหล่านี้นำเสนอข้อได้เปรียบในการปรับปรุงการบริหารทรัพยากรโดยการนำเสนอในรูปแบบที่สอดคล้องกัน ตรงไปตรงมา และไม่คลุมเครือ ด้วยการจ้าง Context Manager เราสามารถลดโค้ดที่ซ้ำซ้อนและเพิ่มความชัดเจนของโค้ดเบสได้
แอปพลิเคชันซอฟต์แวร์มักต้องมีการบันทึกข้อมูลลงในไฟล์ ในกรณีที่ไม่ได้ใช้ตัวจัดการบริบท ผู้ใช้ต้องจัดการการเปิดและปิดไฟล์บันทึกด้วยตนเอง อย่างไรก็ตาม ด้วยการใช้ตัวจัดการบริบท กระบวนการสร้างและการแยกส่วนทรัพยากรการบันทึกสามารถทำให้ง่ายขึ้น ช่วยให้มั่นใจในการดำเนินการบันทึกอย่างมีประสิทธิภาพ ขณะเดียวกันก็รักษาการจัดการที่เหมาะสมของงานที่เกี่ยวข้องด้วย
ด้วยคำสั่ง
การใช้คำสั่ง with
ภายในภาษาการเขียนโปรแกรม Python ช่วยให้นักพัฒนาสามารถใช้ประโยชน์จากความสามารถของตัวจัดการบริบทได้อย่างมีประสิทธิภาพ แม้ว่าจะมีเหตุการณ์พิเศษเกิดขึ้นระหว่างการดำเนินการบล็อกโค้ดที่เกี่ยวข้อง โครงสร้างนี้รับประกันว่าทรัพยากรที่ได้มาทั้งหมดจะถูกละทิ้งอย่างเหมาะสมและบรรลุวัตถุประสงค์ที่ตั้งใจไว้ตามนั้น
with context_manager_expression as resource:
# Code block that uses the resource
# Resource is automatically released when the block exits
ด้วยการใช้คำสั่ง with
ผู้จัดการบริบทจะได้รับอำนาจในการบริหารทรัพยากร ช่วยให้คุณปลดปล่อยความสนใจของคุณไปสู่ความซับซ้อนของตรรกะของโปรแกรมของคุณ
การใช้ตัวจัดการบริบทในตัว
Python มีตัวจัดการบริบทในตัวที่ตอบสนองต่อสถานการณ์ที่แพร่หลาย เช่น การจัดการไฟล์ด้วยฟังก์ชัน open()
และการควบคุมการเชื่อมต่อเครือข่ายผ่านโมดูล ซ็อกเก็ต
การจัดการไฟล์ด้วย open()
ฟังก์ชัน open()
ทำหน้าที่เป็นตัวจัดการบริบทในตัวที่อำนวยความสะดวกในการโต้ตอบกับไฟล์ในการเขียนโปรแกรม Python ยูทิลิตี้นี้มักใช้สำหรับการอ่านหรือเขียนไฟล์และให้ผลออบเจ็กต์ไฟล์เมื่อดำเนินการ ข้อดีหลักประการหนึ่งอยู่ที่การปิดไฟล์โดยอัตโนมัติ ซึ่งช่วยป้องกันข้อมูลเสียหายโดยไม่ได้ตั้งใจเมื่อทำงานภายในบล็อกโค้ดที่ได้รับการจัดการ
with open('file.txt', 'r') as file:
content = file.read()
# Do something with content
# File is automatically closed after exiting the block
การเชื่อมต่อเครือข่ายด้วยซ็อกเก็ต ()
โมดูล ซ็อกเก็ต
นำเสนอตัวจัดการบริบทสำหรับซ็อกเก็ตเครือข่ายที่ช่วยให้มั่นใจได้ถึงการกำหนดค่าที่เหมาะสมและการกำจัดการเชื่อมต่อเครือข่าย ซึ่งช่วยลดความเสี่ยงด้านความปลอดภัยที่อาจเกิดขึ้นที่เกี่ยวข้องกับการเชื่อมต่อที่ถูกยกเลิกอย่างไม่เหมาะสม
import socket
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect(('localhost', 8080))
# Send/receive data over the socket
# Socket is automatically closed after exiting the block
การใช้ตัวจัดการบริบทที่กำหนดเอง
Python อนุญาตให้สร้างตัวจัดการบริบทที่กำหนดเองผ่านทั้งแนวทางแบบคลาสและตามฟังก์ชัน ทางเลือกระหว่างแนวทางเหล่านี้ขึ้นอยู่กับข้อกำหนดเฉพาะของสถานการณ์ปัจจุบัน ในส่วนนี้ เราจะตรวจสอบวิธีการใช้ตัวจัดการบริบทที่กำหนดเองโดยใช้ทั้งสองวิธี
ผู้จัดการบริบทโดยใช้แนวทางแบบคลาส
ในแนวทางแบบอิงคลาส จะกำหนดคลาสที่รวบรวมแนวคิดของการจัดการทรัพยากรผ่านการใช้วิธีการพิเศษสองวิธีที่เรียกว่า \ \ enter\ \ และ \_\ exit\ วิธีการขีดเส้นใต้แบบมหัศจรรย์หรือแบบขีดคู่เหล่านี้มีจุดประสงค์ที่แตกต่างกัน ฝ่ายแรกมีหน้าที่รับผิดชอบในการตั้งค่าและให้ทรัพยากรที่ต้องการ ในขณะที่ฝ่ายหลังทำให้แน่ใจว่าขั้นตอนการล้างข้อมูลอย่างละเอียดได้รับการดำเนินการ โดยไม่คำนึงถึงข้อยกเว้นที่อาจเกิดขึ้นระหว่างการดำเนินการ
class CustomContext:
def __enter__(self):
# Acquire the resource
return resource
def __exit__(self, exc_type, exc_value, traceback):
# Release the resource
pass
เพื่อที่จะดำเนินการหลายกระบวนการพร้อมกันในงานที่กำหนดได้อย่างมีประสิทธิภาพ จำเป็นต้องใช้ตัวจัดการบริบทซึ่งจะปรับปรุงกระบวนการนี้ให้มีประสิทธิภาพมากขึ้น ขณะเดียวกันก็จัดการกับปัญหาต่างๆ เช่น การจัดสรรทรัพยากร การประสานงาน และการแก้ไขข้อผิดพลาด โซลูชันที่เหมาะสมที่สุดควรสร้าง ดำเนินการ และบูรณาการกระบวนการเหล่านี้ได้อย่างราบรื่นโดยอัตโนมัติ เพื่อให้มั่นใจว่ามีการจัดการทรัพยากรและการซิงโครไนซ์ระหว่างกระบวนการอย่างเหมาะสม
import multiprocessing
import queue
class ProcessPool:
def __init__(self, num_processes):
self.num_processes = num_processes
self.processes = []
def __enter__(self):
self.queue = multiprocessing.Queue()
for _ in range(self.num_processes):
process = multiprocessing.Process(target=self._worker)
self.processes.append(process)
process.start()
return self
def __exit__(self, exc_type, exc_value, traceback):
for process in self.processes:
# Sending a sentinel value to signal worker processes to exit
self.queue.put(None)
for process in self.processes:
process.join()
def _worker(self):
while True:
number = self.queue.get()
if number is None:
break
calculate_square(number)
def calculate_square(number):
result = number * number
print(f"The square of {number} is {result}")
if __name__ == "__main__":
numbers = [1, 2, 3, 4, 5]
# Usage
with ProcessPool(3) as pool:
for num in numbers:
pool.queue.put(num)
# Processes are automatically started and
# joined when exiting the 'with' block
ตัวจัดการบริบท ProcessPool จัดการกลุ่มของกระบวนการของผู้ปฏิบัติงานอย่างมีประสิทธิภาพ โดยการจัดสรรการคำนวณ (การคำนวณกำลังสองของจำนวนเต็ม) ระหว่างกระบวนการเหล่านั้นเพื่อการประมวลผลพร้อมกัน ด้วยการควบคุมรูปแบบความเท่าเทียมนี้ จึงเป็นไปได้ที่จะบรรลุการจัดสรรหน่วยประมวลผลกลางที่มีอยู่อย่างรอบคอบมากขึ้น ตลอดจนเร่งการทำงานให้เสร็จสิ้นเมื่อเปรียบเทียบกับการดำเนินการตามลำดับภายในกระบวนการเดี่ยว
ผู้จัดการบริบทโดยใช้แนวทางตามฟังก์ชัน
โมดูล contextlib
มีตัวตกแต่ง @contextmanager
ซึ่งอำนวยความสะดวกในการสร้างตัวจัดการบริบทผ่านฟังก์ชันตัวสร้าง นักตกแต่งช่วยให้สามารถปรับปรุงพฤติกรรมของฟังก์ชันได้โดยการเพิ่มความสามารถใหม่ๆ โดยไม่ต้องเปลี่ยนรูปแบบดั้งเดิม
ภายในบริบทของแนวทางที่ใช้มัณฑนากร การใช้ฟังก์ชันตัวสร้างช่วยให้สามารถใช้ทั้งคำสั่ง ผลผลิต
และ สุดท้าย
เพื่อแบ่งเขตการได้มาและการปล่อยทรัพยากรตามลำดับ
from contextlib import contextmanager
@contextmanager
def custom_context():
# Code to acquire the resource
resource = ...
try:
yield resource # Resource is provided to the with block
finally:
# Code to release the resource
pass
ในการสร้างตัวจัดการบริบทสำหรับการวัดเวลาดำเนินการของบล็อคโค้ดที่กำหนด เราอาจใช้แนวทางเชิงฟังก์ชัน สิ่งนี้เกี่ยวข้องกับการรวมกลไกการจับเวลาภายในบล็อคโค้ดที่ระบุ และต่อมาคำนวณระยะเวลาของการดำเนินการเมื่อเสร็จสิ้น
import time
from contextlib import contextmanager
@contextmanager
def timing_context():
start_time = time.time()
try:
yield
finally:
end_time = time.time()
elapsed_time = end_time - start_time
print(f"Elapsed time: {elapsed_time} seconds")
# Usage
with timing_context():
# Code block to measure execution time
time.sleep(2)
บริบทเวลา\_
การใช้วิธีใดวิธีหนึ่งอาจสร้างตัวจัดการบริบทที่ได้รับการปรับแต่งซึ่งครอบคลุมความซับซ้อนของการจัดการทรัพยากรที่ซับซ้อนและงานที่เกิดซ้ำ ด้วยเหตุนี้จึงเพิ่มประสิทธิภาพการจัดระเบียบโค้ดและอำนวยความสะดวกในการบำรุงรักษา
การซ้อนผู้จัดการบริบท
การซ้อนตัวจัดการบริบทอาจมีข้อได้เปรียบในสถานการณ์ที่จำเป็นต้องมีการจัดการทรัพยากรหลายรายการพร้อมกัน ด้วยการใช้บริบทที่ซ้อนกัน เราสามารถรักษาลำดับการดำเนินงานได้อย่างต่อเนื่องและไร้ข้อผิดพลาด ในขณะเดียวกันก็รับและปล่อยทรัพยากรแต่ละรายการอย่างขยันขันแข็งตามที่ต้องการ
ในบางกรณี อาจจำเป็นสำหรับโปรแกรมในการดึงข้อมูลจากไฟล์และจัดเก็บไว้ในฐานข้อมูล การจัดการทรัพยากรที่แตกต่างกันทั้งสองนี้ถือเป็นความท้าทายที่สามารถแก้ไขได้ผ่านการใช้ตัวจัดการบริบทที่ซ้อนกันภายในกันและกัน
import sqlite3
class DatabaseConnection:
def __enter__(self):
self.connection = sqlite3.connect('lite.db')
return self.connection
def __exit__(self, exc_type, exc_value, traceback):
self.connection.close()
# Using nested context managers
with DatabaseConnection() as db_conn, open('data.txt', 'r') as file:
cursor = db_conn.cursor()
# Create the table if it doesn't exist
cursor.execute("CREATE TABLE IF NOT EXISTS data_table (data TEXT)")
# Read data from file and insert into the database
for line in file:
data = line.strip()
cursor.execute("INSERT INTO data_table (data) VALUES (?)", (data,))
db_conn.commit()
ในกรณีนี้ ตัวจัดการบริบท DatabaseConnection
มีหน้าที่จัดการการเชื่อมต่อฐานข้อมูล ในขณะที่ตัวจัดการบริบท open()
โดยธรรมชาติจะดูแลการจัดการไฟล์
เพื่อจัดการทั้งไฟล์และการเชื่อมต่อฐานข้อมูลอย่างมีประสิทธิภาพ สิ่งสำคัญคือต้องรวมบริบททั้งสองนี้ไว้ในคำสั่งเดียว สิ่งนี้ทำให้แน่ใจได้ว่าการปล่อยทรัพยากรทั้งสองอย่างเหมาะสมจะเกิดขึ้นหากมีข้อยกเว้นใดๆ เกิดขึ้นระหว่างกระบวนการอ่านไฟล์หรือการแทรกฐานข้อมูล
การปรับแต่งฟังก์ชั่นด้วยมัณฑนากร
การดูแลทรัพยากรอย่างมีประสิทธิผลเป็นข้อกำหนดเบื้องต้นขั้นพื้นฐานสำหรับประสิทธิภาพและความเสถียรสูงสุดในระบบซอฟต์แวร์ การเกิดการรั่วไหลของทรัพยากรอาจนำไปสู่การสะสมของหน่วยความจำที่มากเกินไป ส่งผลให้ประสิทธิภาพลดลงและช่องโหว่ที่อาจเกิดขึ้น ได้รับการพิสูจน์แล้วว่าการใช้ตัวจัดการบริบทเป็นแนวทางที่ได้รับการปรับปรุงในการจัดการกับความท้าทายที่เกี่ยวข้องกับการจัดการทรัพยากร