2015-06-12 12 views
5

Tôi đang làm việc trên một ứng dụng phải hỗ trợ các kết nối máy khách-máy chủ. Để làm được điều đó, tôi đang sử dụng mô-đun lốc xoáy cho phép tôi tạo WebSockets. Tôi dự định sẽ luôn hoạt động, ít nhất là phía máy chủ. Vì vậy, tôi rất lo lắng về hiệu suất và mức sử dụng bộ nhớ của từng đối tượng được tạo trên các kết nối này. Tôi đã bắt đầu làm các xét nghiệm để phát hiện khi thực sự các đối tượng này bị loại bỏ bởi thư viện. Lấy mã ví dụ và tôi ghi đè lên các phương pháp __del__()python - Khi nào WebSocketHandler và TornadoWebSocketClient hoàn toàn bị xóa?

server.py

#! /usr/bin/env python 
import tornado.httpserver 
import tornado.websocket 
import tornado.ioloop 
import tornado.web 
import gc, sys 
import resource 

class WSHandler(tornado.websocket.WebSocketHandler): 
    def open(self): 
     print 'new connection' 
     self.write_message("h") 

    def check_origin(self, origin): 
     return True 

    def on_message(self, message): 
     print "Message: " + message 

    def on_close(self): 
     print 'Closed' 
     print 'GC count: ' + str(len(gc.get_referrers(self))) 

    def __del__(self): 
     print "DELETED" 

application = tornado.web.Application([ 
    (r'/s', WSHandler), 
]) 


if __name__ == "__main__": 
    http_server = tornado.httpserver.HTTPServer(application) 
    http_server.listen(8888) 
    tornado.ioloop.IOLoop.instance().start() 

client.py

#! /usr/bin/env python 
from ws4py.client.tornadoclient import TornadoWebSocketClient 
from tornado import ioloop 

class MainClient(TornadoWebSocketClient): 
    def opened(self): 
     print "Connected" 

    def received_message(self, message): 
     print "Message" 

     #I close the connection 
     self.close() 

    def closed(self, code, reason=None): 
     print "Closed" 
     ioloop.IOLoop.instance().stop() 

    def __del__(self): 
     print "DELETED" 

if __name__ == "__main__": 
    ws = MainClient('ws://localhost:8888/s', protocols=['http-only', 'chat']) 
    ws.connect() 

    ioloop.IOLoop.instance().start() 

Khi khách hàng nhận được một tin nhắn, nó đóng kết nối. Tôi hy vọng rằng cả hai đối tượng đã bị loại bỏ, bởi vì kết nối đã được đóng lại, và do đó gọi phương thức __del__(), nhưng điều đó đã không xảy ra.

sản lượng máy chủ: sản lượng

new connection 
Closed 
GC count: 6 

khách hàng:

Connected 
Message 
Closed 

Như bạn có thể nhìn thấy nó không in DELETED câu mà tôi đã mong đợi từ các phương pháp __del__().

--edited--

Ngoài ra tôi đã thêm dòng in số lượng tài liệu tham khảo trong đó có các GC của đối tượng đó tại thời điểm đóng kết nối. Điều này chứng minh rằng có thực sự tham khảo chu kỳ.

-----

Rõ ràng là các lớp học mà tôi sẽ sử dụng sẽ phức tạp hơn so với những người, nhưng giúp tôi hiểu được hành vi của cả hai đối tượng, đó là những gì tôi thực sự tìm cách biết: khi họ có bị xóa không? Nó giải phóng bộ nhớ khi xóa chúng? hoặc bằng cách nào đó trở thành bằng cách nào đó? hoặc ¿cách xóa đối tượng một cách rõ ràng?

Tôi đọc số tornado.websocket.WebSocketHandlerdocumentation, nó giải thích cho tôi khi đối tượng bị "đóng", nhưng tôi không biết khi nào bộ nhớ được giải phóng.

Trả lời

3

Mã WebSocket hiện có chứa một số chu trình tham chiếu, có nghĩa là các đối tượng không được làm sạch cho đến khi GC đầy đủ tiếp theo. Thậm chí tệ hơn, các phương thức __del__ thực sự có thể ngăn chặn việc xóa một đối tượng (trong python 3.3 và cũ hơn: https://docs.python.org/3.3/library/gc.html#gc.garbage), do đó rất khó để biết khi nào mọi thứ thực sự bị xóa. Thay vào đó, bạn sẽ chỉ cần tải thử nghiệm hệ thống của bạn và xem nếu dấu chân bộ nhớ của nó tăng theo thời gian.

(Patches để phá vỡ các chu kỳ tài liệu tham khảo sau khi một kết nối được đóng sẽ được hoan nghênh)

+0

Để tránh những chu kỳ tài liệu tham khảo, sẽ được 'weakref' một lựa chọn? Hoặc không có gì để làm whit nó? –

+1

Tôi không chắc liệu 'weakref' có giúp các chu trình trong GC hiện tại hay không (một chu trình bao gồm các tham chiếu yếu vẫn là một chu kỳ).Trong trường hợp này, chúng tôi đã có một số mã dọn dẹp rõ ràng (nơi chúng tôi đóng IOStream và xóa trình xử lý khỏi IOLoop), vì vậy chúng tôi chỉ cần đảm bảo rằng bất kỳ thuộc tính nào có thể gây ra chu kỳ (và không còn cần thiết) được đặt thành Không . –

Các vấn đề liên quan