Trước tiên, để trả lời câu hỏi của bạn trong tiêu đề: filter
chỉ là một chức năng. Do đó, an toàn luồng của nó sẽ dựa vào cấu trúc dữ liệu mà bạn sử dụng nó.
Như đã nêu trong các nhận xét, danh sách hoạt động chính là an toàn luồng trong CPython và được bảo vệ bởi GIL, nhưng đó chỉ là chi tiết thực hiện của CPython mà bạn không nên dựa vào. Ngay cả khi bạn có thể dựa vào nó, an toàn luồng của một số thao tác của chúng có thể không có nghĩa là loại an toàn chủ đề bạn có nghĩa là:
Vấn đề là việc lặp lại chuỗi với filter
nói chung không phải là hoạt động nguyên tử. Trình tự có thể được thay đổi trong khi lặp lại. Tùy thuộc vào cấu trúc dữ liệu bên dưới trình vòng lặp của bạn, điều này có thể gây ra nhiều hiệu ứng lạ hoặc ít. Một cách để khắc phục vấn đề này là bằng cách lặp qua một bản sao của chuỗi được tạo ra với một hành động nguyên tử. Cách dễ nhất để làm điều này cho chuỗi tiêu chuẩn như tuple
, list
, string
là với các nhà điều hành lát như thế này:
filter(lambda x: x[0] == "in", l[:])
Ngoài này không nhất thiết phải là thread-an toàn cho dữ liệu các loại khác, có một vấn đề với mặc dù điều này : nó chỉ là một bản sao nông. Vì các phần tử của danh sách của bạn dường như giống như danh sách, một luồng khác có thể song song làm del l[1000][:]
để trống một trong các danh sách bên trong (cũng được chỉ ra trong bản sao nông của bạn). Điều này sẽ làm cho biểu thức lọc của bạn không thành công với một số IndexError
.
Tất cả những gì đã nói, không phải là một sự xấu hổ khi sử dụng khóa để bảo vệ quyền truy cập vào danh sách của bạn và tôi chắc chắn sẽ giới thiệu nó. Tùy thuộc vào cách dữ liệu của bạn thay đổi và cách bạn làm việc với dữ liệu được trả lại, nó thậm chí có thể là khôn ngoan để sao chép sâu các phần tử trong khi giữ khóa và trả lại các bản sao đó. Bằng cách đó bạn có thể đảm bảo rằng một khi trở lại điều kiện bộ lọc sẽ không đột ngột thay đổi cho các phần tử trả về.
Wrt. mã số Logger
của bạn: Tôi không chắc chắn 100% cách bạn dự định sử dụng và nếu điều đó quan trọng đối với bạn để chạy một số chuỗi trên một hàng đợi và join
chúng. Điều kỳ lạ đối với tôi là bạn không bao giờ sử dụng Queue.task_done()
(giả sử rằng self.log
của nó là Queue
). Ngoài ra bỏ phiếu của bạn trong hàng đợi có khả năng lãng phí. Nếu bạn không cần join
của thread, tôi muốn đề nghị ít nhất là biến việc mua lại khóa xung quanh:
class Logger(threading.Thread):
def __init__(self, log):
super(Logger, self).__init__()
self.daemon = True
self.log = log
self.data = []
self.data_lock = threading.Lock()
def run(self):
while True:
l = self.log.get() # thread will sleep here indefinitely
with self.data_lock:
self.data.append(l)
self.log.task_done()
def get_data(self, cond):
with self.data_lock:
d = filter(cond, self.data)
# maybe deepcopy d here
return d
Bên ngoài bạn vẫn có thể làm log.join()
để đảm bảo rằng tất cả các yếu tố của log
hàng đợi được xử lý.
Bạn nên lo lắng về danh sách không phải là 'bộ lọc' và không, danh sách không an toàn thread – thefourtheye
Fitler trên bản sao của danh sách. –
@thefourtheye http://stackoverflow.com/questions/6319207/are-lists-thread-safe mâu thuẫn với phản hồi của bạn một chút :) Tôi tin rằng danh sách chính họ là threadsafe và GIL bảo vệ chống tham nhũng dữ liệu theo cách này (* trong hầu hết các trường hợp *). –