Why does Paramiko hang if you use it while loading a module?
将以下内容放入一个文件hello.py(如果您还没有找到,还可以将
1 2 3 4 5 6 7 8 | hostname,username,password='fill','these','in' import paramiko c = paramiko.SSHClient() c.set_missing_host_key_policy(paramiko.AutoAddPolicy()) c.connect(hostname=hostname, username=username, password=password) i,o,e = c.exec_command('ls /') print(o.read()) c.close() |
适当地填写第一行。
现在类型
1 | python hello.py |
您将看到一些ls输出。
现在改为键入
1 | python |
然后从解释器类型中
1 | import hello |
瞧!它挂起来了!如果您将代码包装在一个函数
为什么在模块初始化中使用Paramiko时挂起?Paramiko是如何知道在模块初始化过程中使用它的?
Paramiko为底层传输使用单独的线程。您不应该有一个模块产生一个线程作为导入的副作用。据我所知,有一个导入锁可用,因此当模块的子线程尝试另一个导入时,它可能无限期阻塞,因为主线程仍然持有该锁。(可能还有其他我不知道的问题)
一般来说,模块在导入时不应该有任何副作用,否则会得到不可预知的结果。只要用
[编辑]我似乎无法创建重现这种死锁的简单测试用例。我仍然认为这是导入的线程问题,因为auth代码正在等待一个永远不会触发的事件。这可能是paramiko或python中的一个bug,但好消息是,如果您做得正确,就不应该看到它;)
这是一个很好的例子,为什么你总是想要最小化副作用,为什么函数式编程技术变得越来越流行。
正如Jimb指出的那样,当python尝试在ssh连接尝试期间首次使用时隐式导入
一般来说,您不能过分强调,以免模块在导入时自动生成新线程。如果可以的话,尽量避免使用魔法模块代码,因为它几乎总是会导致不必要的副作用。
如前所述,解决您的问题的简单而明智的方法是将您的代码放在
(不推荐)另一个解决方法是在调用
那么这个问题的根本原因是什么呢?
分析(简单密码验证)
提示:如果要在python导入中调试线程并设置
这基本上是作为
EDOCX1 14打印我们的日志消息"开始线程",然后继续到EDCOX1 15。
如果收到服务器横幅,它会尝试UTF-8解码响应字符串
所以一个不好的解决方法就是只导入一次UTF-8解码器,这样就不会因为模块导入副作用而阻塞特定的导入。(
固定
脏修复-不推荐
1 2 3 4 5 6 7 8 9 | import paramiko hostname,username,password='fill','these','in' ''.decode('utf-8') # dirty fix c = paramiko.SSHClient() c.set_missing_host_key_policy(paramiko.AutoAddPolicy()) c.connect(hostname=hostname, username=username, password=password) i,o,e = c.exec_command('ls /') print(o.read()) c.close() |
好固定
1 2 3 4 5 6 7 8 9 | import paramiko if __name__ == '__main__': hostname,username,password='fill','these','in' c = paramiko.SSHClient() c.set_missing_host_key_policy(paramiko.AutoAddPolicy()) c.connect(hostname=hostname, username=username, password=password) i,o,e = c.exec_command('ls /') print(o.read()) c.close() |
参考参数问题跟踪:第104期
.decode("utf-8")对我不起作用,最终我做到了这一点。
1 2 3 | from paramiko import py3compat # dirty hack to fix threading import lock (issue 104) by preloading module py3compat.u("dirty hack") |
我有一个实现了这个的Paramiko包装器。https://github.com/bucknerns/sshaolin