python - Class::__del__:尝试在析构函数中使用成员对象释放资源失败
问题描述
我在Test
下面有一个简单的类,它启动一个 Google Compute Engine VM,然后通过调用函数(显式)或依赖对象破坏(通过__del__
(隐式))来停止它。
class Test:
def __init__(self):
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = 'secret.json'
self._compute = googleapiclient.discovery.build('compute',
'v1',
cache_discovery=False)
print('starting vm')
req = self._compute.instances().start(project='test-project',
zone='us-east1-b',
instance='test-vm',
requestId=uuid.uuid1())
self.execute(req)
self._running = True
def stop(self):
print('stopping vm')
req = self._compute.instances().stop(project='test-project',
zone='us-east1-b',
instance='test-vm',
requestId=uuid.uuid1())
self.execute(req)
self._running = False
def execute(self, req):
print(f'method({req.methodId})')
resp = req.execute()
while resp['status'] != 'DONE':
time.sleep(1)
resp = req.execute()
return resp
def __del__(self):
if self._running:
print('stopping in destructor')
self.stop()
该类Test
的交互方式如下:
if __name__ == '__main__':
print('start test')
t = Test()
print('vm running, wait 5 seconds')
time.sleep(5)
if len(sys.argv) == 2 and sys.argv[1] == 'stop':
t.stop()
print('test done')
当使用显式方法时(即:在对象开始被破坏t.stop()
之前调用),VM 停止正常:
$ ./test.py stop
start test
starting vm
method(compute.instances.start)
vm running, wait 5 seconds
stopping vm
method(compute.instances.stop)
test done
但是,当使用隐式方法时(即:依赖t
超出范围并已Test::__del__
调用),我从googleapiclient
堆栈内抛出异常:
$ ./test.py
start test
starting vm
method(compute.instances.start)
vm running, wait 5 seconds
test done
stopping in destructor
stopping vm
method(compute.instances.stop)
Exception ignored in: <bound method Test.__del__ of <__main__.Test object at 0x7fe091720320>>
Traceback (most recent call last):
File "./test.py", line 46, in __del__
File "./test.py", line 32, in stop
File "./test.py", line 37, in execute
File "/src/test/.venv/lib/python3.6/site-packages/googleapiclient/_helpers.py", line 130, in positional_wrapper
File "/src/test/.venv/lib/python3.6/site-packages/googleapiclient/http.py", line 846, in execute
File "/src/test/.venv/lib/python3.6/site-packages/googleapiclient/http.py", line 183, in _retry_request
File "/src/test/.venv/lib/python3.6/site-packages/googleapiclient/http.py", line 164, in _retry_request
File "/src/test/.venv/lib/python3.6/site-packages/google_auth_httplib2.py", line 198, in request
File "/src/test/.venv/lib/python3.6/site-packages/httplib2/__init__.py", line 1926, in request
File "/src/test/.venv/lib/python3.6/site-packages/httplib2/__init__.py", line 1595, in _request
File "/src/test/.venv/lib/python3.6/site-packages/httplib2/__init__.py", line 1502, in _conn_request
File "/usr/lib/python3.6/http/client.py", line 1239, in request
File "/usr/lib/python3.6/http/client.py", line 1285, in _send_request
File "/usr/lib/python3.6/http/client.py", line 1234, in endheaders
File "/usr/lib/python3.6/http/client.py", line 1026, in _send_output
File "/usr/lib/python3.6/http/client.py", line 986, in send
File "/usr/lib/python3.6/ssl.py", line 975, in sendall
File "/usr/lib/python3.6/ssl.py", line 944, in send
File "/usr/lib/python3.6/ssl.py", line 642, in write
ssl.SSLError: Underlying socket connection gone (_ssl.c:2067)
问题:
- 我使用
Test::__del__
来停止我的虚拟机是非法的吗? - 到时间
Test::__del__
被调用时,访问不再安全self._compute
吗? - 这是 Google API 客户端中的错误吗?
- 有没有办法依靠我的对象的破坏来触发停止我的虚拟机?
解决方案
推荐阅读
- angular - 带有 ICU 消息格式的 angular-l10n 复数
- doctrine-orm - Doctrine 是否使用 MySQL 索引?
- vba - VBA通过字体名称而不是字体索引更改Visio字体样式?
- python - 为外汇数据绘制 WADL 时出现 ValueError
- google-apps-script - 带有部分和卡片列表的卡片 - Gmail 插件
- python - 如何注释一个以另一个函数作为参数的函数?
- html - Xpath 在 id 和 div 之间使用通配符?
- r - 如何从 XML 文件中选择特定信息?在 R 或其他平台
- java - RxJavaPlugins,背后的模式
- visual-studio - 从 vs2017 解决方案中自动排除具有特定名称的文件夹/文件