Hướng dẫn sử dụng yếu Python

Trong khi làm việc với tính khả dụng cao của các dịch vụ AI của chúng tôi, cả nhiều quy trình và luồng đều được sinh ra, chấm dứt và hồi sinh lại. Nếu một quá trình bị chấm dứt, các tài nguyên được phân bổ chỉ đơn giản là được giải phóng, nhưng với các luồng, quá trình này không đơn giản như vậy. Trong bài viết này, tôi sẽ giải thích cách tham chiếu yếu có thể thực sự hữu ích trong những tình huống này

Một phần dịch vụ của chúng tôi yêu cầu phản ứng với các sự kiện thời gian thực tích lũy trong hàng đợi có khả năng chịu lỗi. Để xử lý những sự kiện này, chúng tôi đã phát triển một ứng dụng tiêu dùng có tính sẵn sàng cao, đó là loại hàng đợi bất khả tri

Trình tiêu dùng hàng đợi của chúng tôi quản lý công nhân khởi động trong các luồng hoặc quy trình riêng lẻ, giám sát chúng, khởi động lại trong trường hợp chấm dứt và phát hiện các luồng hoặc quy trình bị treo

Tất cả những gì chúng ta cần cho một dự án là xác định trình xử lý, trình xử lý này sẽ được gọi khi sử dụng sự kiện. Đối với dự án này, giả sử trình xử lý truy xuất đường dẫn AWS s3 từ một sự kiện, tải tệp xuống và thực hiện một số nội dung 'AI' với nội dung của nó. Để làm việc với AWS, có một thư viện tuyệt vời tên là boto3. Khi xử lý boto3, AWS khuyến nghị ‘’

Điều này có nghĩa là, một mặt, chúng ta chỉ cần viết mã trình xử lý sự kiện và bỏ qua các luồng cũng như việc quản lý chúng, nhưng mặt khác, chúng ta nên tạo một phiên bản tài nguyên AWS khi tạo luồng (cụ thể là lệnh gọi trình xử lý đầu tiên) và sau đó giải phóng nó trên luồng.

Để tạo và xóa tài nguyên AWS trên mỗi lệnh gọi trình xử lý là không tối ưu vì mục tiêu của chúng tôi là bắt đầu và kết thúc luồng, đồng thời trong thời gian chạy luồng có thể xảy ra hàng nghìn lệnh gọi trình xử lý

Đó là lý do tại sao chúng tôi sử dụng Python weakref.WeakKeyDictionary với một tinh chỉnh — chúng tôi đặt đối tượng luồng làm khóa và tài nguyên AWS làm giá trị. Do tính năng tham chiếu yếu, nếu các đối tượng chính (phiên bản luồng) bị xóa bởi GC (trình thu gom rác), thì tham chiếu đến giá trị (tài nguyên) cũng sẽ bị xóa và sau đó GC cũng có thể xóa nó (nếu không có tham chiếu nào khác đến . Hãy nhớ rằng Python GC sử dụng kỹ thuật đếm tham chiếu

Dưới đây là đoạn mã về cách chúng tôi gán tài nguyên s3 cho các luồng

Và khi chúng tôi sử dụng AWS SQS làm hàng đợi có khả năng chịu lỗi, chúng tôi vẫn tuân theo khuyến nghị của AWS ngoài việc duy trì nhóm tham chiếu yếu gồm các máy khách SQS

Người giám sát của khách hàng quan sát các luồng, loại bỏ các luồng chết và bắt đầu các luồng mới, điều này dẫn đến việc loại bỏ các đối tượng boto3, liên quan đến các luồng chết khỏi nhóm

Điều gì về chủ đề an toàn? . Câu trả lời là cả có và không'. Sẽ không an toàn cho luồng nếu bạn cố lặp lại từ điển và một luồng đồng thời thêm phần tử mới vào đó, nhưng nếu các luồng chỉ thêm các mục thì không sao. weakref.WeakKeyDictionary là trình bao bọc của Python trên từ điển tích hợp. Python đảm bảo các nguyên tử cho các phương thức trong các nguyên hàm tích hợp sẵn và việc thêm các mục vào từ điển cũng là nguyên tử. weakref.WeakKeyDictionary không được tích hợp sẵn, đó là mã Python. Chúng tôi đã điều tra mã nguồn của nó và không tìm thấy lý do tại sao nó không an toàn cho luồng và chúng tôi cũng không gặp bất kỳ sự cố nào khi sử dụng. Chúng ta cũng nên xem xét mã nguồn weakref.WeakKeyDictionary để đảm bảo rằng nó cũng an toàn cho luồng

mã để

def __setitem__(self, key, value):
self.data[ref(key, self._remove)] = value

Như bạn thấy trong ví dụ, nó chỉ thêm một phần tử mới vào từ điển tích hợp vì

def remove(k, selfref=ref(self)):
self = selfref()
if self is not None:
if self._iterating:
self._pending_removals.append(k)
else:
del self.data[k]
self._remove = remove
1. Mặc dù vậy, có một mẹo trong đó nó bọc một khóa thành một tham chiếu yếu và đăng ký cuộc gọi lại
def remove(k, selfref=ref(self)):
self = selfref()
if self is not None:
if self._iterating:
self._pending_removals.append(k)
else:
del self.data[k]
self._remove = remove
2, cuộc gọi này được gọi nếu khóa bị xóa bởi GC. Trong trường hợp của chúng tôi, điều này xảy ra khi chuỗi kết thúc và bị người giám sát xóa khỏi nhóm

Hãy xem xét

def remove(k, selfref=ref(self)):
self = selfref()
if self is not None:
if self._iterating:
self._pending_removals.append(k)
else:
del self.data[k]
self._remove = remove
3 để đảm bảo an toàn cho luồng của nó

def remove(k, selfref=ref(self)):
self = selfref()
if self is not None:
if self._iterating:
self._pending_removals.append(k)
else:
del self.data[k]
self._remove = remove

Như bạn có thể thấy, hàm

def remove(k, selfref=ref(self)):
self = selfref()
if self is not None:
if self._iterating:
self._pending_removals.append(k)
else:
del self.data[k]
self._remove = remove
4 cũng thực hiện những việc nguyên tử (
def remove(k, selfref=ref(self)):
self = selfref()
if self is not None:
if self._iterating:
self._pending_removals.append(k)
else:
del self.data[k]
self._remove = remove
5 theo mặc định)

Bây giờ chúng ta đã hiểu cách gọi lại tham chiếu yếu được tạo và gọi trong

def remove(k, selfref=ref(self)):
self = selfref()
if self is not None:
if self._iterating:
self._pending_removals.append(k)
else:
del self.data[k]
self._remove = remove
6, chúng ta có thể mở rộng nó để thực hiện thêm những việc khác khi loại bỏ luồng. Hãy tưởng tượng rằng chúng ta cần khởi động một máy chủ khi tạo chuỗi và dừng nó khi kết thúc. Sau đó, một mã có thể được làm lại như thế này

Hãy cũng đảm bảo rằng nó có thể hoạt động. Chỉ cần thay đổi mã một chút để làm cho nó trực quan hơn

Và sau cuộc gọi

________số 8_______

Nó hoạt động ngay cả khi luồng tăng ngoại lệ

kết quả cuộc gọi

$ python script.pyException: BOOM!
pool size is 1
before callback
callback is called
resource is deleted
after callback
pool size is 0

Tham chiếu yếu là một tính năng mạnh mẽ có thể được sử dụng ở những nơi khác nhau để tránh các vấn đề về quản lý bộ nhớ. Nếu bạn đã bắt đầu quan tâm đến nó, bạn cũng có thể xem cách tránh rò rỉ bộ nhớ với các tham chiếu vòng trong Python

Điểm yếu trong Python là gì?

Mô-đun tham chiếu yếu cho phép lập trình viên Python tạo các tham chiếu yếu đến các đối tượng . Sau đây, thuật ngữ tham chiếu có nghĩa là đối tượng được tham chiếu bởi một tham chiếu yếu.

Khi nào nên sử dụng Weakref Python?

Python chứa mô-đun yếu tham chiếu tạo tham chiếu yếu đến một đối tượng. Nếu không có tham chiếu mạnh đến một đối tượng, trình thu gom rác có thể tự do sử dụng bộ nhớ cho các mục đích khác. Tham chiếu yếu được sử dụng để triển khai bộ đệm và ánh xạ chứa dữ liệu lớn .

Việc sử dụng các tài liệu tham khảo yếu là gì?

Tham chiếu yếu cho phép trình thu gom rác thu thập đối tượng trong khi vẫn cho phép ứng dụng truy cập đối tượng . Tham chiếu yếu chỉ hợp lệ trong khoảng thời gian không xác định cho đến khi đối tượng được thu thập khi không tồn tại tham chiếu mạnh.

Tràn ngăn xếp Python tham chiếu yếu là gì?

Tham chiếu yếu cho phép bạn tạo tham chiếu đến một đối tượng sẽ không làm tăng số lượng tham chiếu . Số lượng tham chiếu được sử dụng bởi Trình thu gom rác của python khi nó chạy. bất kỳ đối tượng nào có số tham chiếu bằng 0 sẽ được thu gom rác.