我的Python代码可以处理多个物联网设备,可以同时使用ssh进入多个设备,没有任何问题(使用pexpect库)。这是在multiprocessing. pool. ThreadPool中完成的。在重新启动我的MacBook之后,ping线程池中的多个主机也可以正常工作。ping 55个活动主机一次,每个主机大约需要一秒钟,ping时间和预期的一样。然而,随着时间的推移,ping代码的工作开始变得很糟糕。Ping时间增加,直到后来启动的线程超时。第一个启动的线程成功地使用了合理的ping时间,但ping操作的墙时间非常长--几秒钟后返回的ping时间低于100毫秒。
我简化了一些测试代码以隔离问题:
import subprocess
import time
from multiprocessing.pool import ThreadPool as Pool
import pythonping
import ping3
# ping using a subprocess and ping command
def ping_1(ip):
a = time.time()
cmd = ['ping', '-c 1', '-W 2000', ip]
result = subprocess.run(cmd, capture_output=True, check=False)
b = time.time()
res = result.stdout.decode('utf-8')
idx = res.find('time=')+len('time=')
rtt = res[idx:res.find(' ', idx)]
if not rtt and result.returncode == 0:
print(res)
rtt = '0' if not rtt else rtt
return a, b, result.returncode == 0, float(rtt)
# ping using pythonping library
def ping_2(ip):
a = time.time()
result = pythonping.ping(ip, count=1, timeout=2.0)
b = time.time()
return a, b, result.success(), result.rtt_avg*1000
# ping using ping3 library
def ping_3(ip):
a = time.time()
result = ping3.ping(ip, timeout=2.0)
b = time.time()
return a, b, result is not None, result*1000 if result else result
# a dummy function to make sure threading works
def ding(_):
a = time.time()
time.sleep(1)
b = time.time()
return a, b
# executes one of the above in a thread pool
def test(func, ip_list, n_proc=20):
start_time = time.time()
if n_proc == 0:
result = map(func, ip_list)
else:
with Pool(processes=n_proc) as pool:
result = pool.map(func, ip_list)
print(f'{f"start(s)":>8} {f"end(s)":>6} {"success":>7} {"ping time (ms)":>14}')
for start, end, success, ping_ms in result:
print(f'{f"{start-start_time:0.3f}":>8} {f"{end-start_time:0.3f}":>6} '
f'{str(success):>7} {round(ping_ms):>14}')
# ping using n non-blocking subprocesses
def test2(ip_list):
procs = [subprocess.Popen(['ping', '-c 1', '-W 2000', ip]) for ip in ip_list]
while any(proc.poll() is None for proc in procs):
time.sleep(0.1)
return [proc.poll() for proc in procs]
重新启动后,我得到如下所示的输出。
>>> junk.test(junk.ping_1, ips, 30)
start(s) end(s) success ping time (ms)
0.020 0.071 True 31
0.021 0.115 True 58
0.026 0.118 True 32
0.029 0.079 True 34
0.031 0.098 True 32
0.041 0.097 True 31
0.051 0.141 True 55
0.054 0.142 True 33
0.071 0.288 True 56
0.072 0.141 True 29
0.079 0.133 True 30
0.087 0.190 True 35
0.098 0.184 True 32
0.098 0.256 True 32
0.098 0.308 True 30
0.115 0.213 True 35
0.118 0.307 True 36
0.140 0.394 True 51
0.141 0.264 True 53
0.141 0.235 True 36
0.142 0.412 True 36
0.142 0.236 True 27
0.142 0.270 True 33
0.142 0.186 True 28
0.148 0.247 True 31
0.163 0.253 True 34
0.176 0.353 True 33
0.184 0.401 True 30
0.185 0.333 True 32
0.186 0.347 True 32
0.190 0.441 True 56
0.213 0.353 True 34
0.221 0.386 True 32
0.235 0.344 True 35
0.236 0.374 True 56
0.248 0.307 True 32
0.248 0.447 True 51
0.253 0.447 True 31
0.256 0.423 True 29
0.264 0.321 True 32
0.270 0.412 True 51
0.288 0.449 True 32
0.303 0.443 True 34
0.307 0.368 True 31
0.307 0.380 True 30
0.308 0.472 True 32
0.314 0.458 True 33
0.321 0.434 True 29
0.333 0.452 True 30
0.337 0.448 True 28
0.344 0.412 True 29
0.347 0.448 True 33
0.353 0.442 True 28
0.353 0.501 True 55
0.371 0.464 True 34
经过几个小时到几天的正常运行时间,它逐渐变成这样:
start(s) end(s) success ping time (ms)
0.005 0.084 True 48
0.005 10.217 True 39
0.009 10.242 True 44
0.012 10.207 True 51
0.013 10.156 True 171
0.029 10.217 True 50
0.035 10.177 True 48
0.053 10.157 True 166
0.060 10.216 True 483
0.061 10.124 True 689
0.061 10.091 True 944
0.085 10.111 True 945
0.086 10.121 True 684
0.095 10.100 True 955
0.113 10.089 True 950
0.126 10.117 True 959
0.136 10.150 True 966
0.136 10.141 True 964
0.147 9.283 True 1003
0.147 10.176 True 973
0.148 9.245 True 1009
0.148 10.175 True 976
0.164 10.231 True 980
0.173 10.177 True 973
0.179 10.236 True 983
0.194 9.276 True 997
0.203 9.257 True 1000
0.219 9.721 True 1470
0.220 9.247 True 1007
0.245 9.934 True 1960
0.238 9.945 True 1947
9.246 13.269 False 0
9.247 13.271 False 0
9.257 13.282 False 0
9.277 13.291 False 0
9.283 13.303 False 0
9.722 13.747 False 0
9.935 13.954 False 0
9.945 13.967 False 0
10.090 14.107 False 0
10.091 14.116 False 0
10.101 14.126 False 0
10.111 14.136 False 0
10.117 14.153 False 0
10.121 14.153 False 0
10.125 14.236 False 0
10.142 14.170 False 0
10.151 14.163 False 0
10.156 14.187 False 0
10.157 14.213 False 0
10.175 14.247 False 0
10.176 14.205 False 0
10.177 14.219 False 0
10.177 14.191 False 0
10.207 14.230 False 0
上面代码中的所有ping方法都遵循相同的模式。(ping 3似乎在重启后也表现得很奇怪,但随着时间的推移,情况会变得更糟。)我尝试过通过WiFi、有线以太网和手机的热点功能来重启所有Python内核,升级Python(通过Anaconda),升级MacOS(主要和次要),升级VPN客户端(思科)、删除防病毒软件(MS Defender)。一旦它进入这种状态,除了重新启动之外,没有任何东西可以修复它。该模式在所有列出的更新中都会持续存在。
有趣的是,当计算机处于这种状态时,我可以启动一个Docker容器,用相同的Python版本运行相同的代码,效果很好。关闭Docker Desktop既不能修复问题,也不能防止问题发生,如果在重新启动后立即关闭的话。
我也观察过Angry IP Scanner(设置为使用128个线程)的操作。在重新启动后,一个特定的IP扫描需要14秒。在ping问题出现后,同样的扫描需要145秒!
我尝试了30次并行ping我的路由器,问题也出现了,尽管程度要小得多。ping没有超时,只是对于较晚启动的线程来说时间更长。第一个线程在〈10 ms内得到一个ping。最后一个线程测量的ping时间为数百毫秒。
Update 1:昨晚睡觉前,我用愤怒的IP扫描仪运行了扫描,大约花了15秒。今天早上花了90秒。问题似乎已经表现出来,而计算机不在使用中。
Update 2:再次,问题突然出现,而我离开了电脑。它可能与Mac的省电功能有什么关系?在这两个最近发生的事件,MacBook连接到交流电源,所以省电功能被部分禁用(“防止Mac从自动睡眠时,显示器关闭”在设置中启用)。
1条答案
按热度按时间r3i60tvu1#
这里的问题出在思科VPN软件上。不是客户端本身,而是一些与之配套的叫做包过滤器的辅助扩展。由于它们是系统网络扩展,即使VPN断开连接,它们也是活动的。引入了一个bug在Cisco AnyConnect for MacOS 4.10版中(或重新引入),并在5.0版中继续使用(重命名为Cisco Secure Client)。它会导致非常高的CPU负载(在我的系统上钉住一个处理器核心)在网络活动期间,尤其是并行操作,如发生在主机扫描期间。性能问题是如此严重,愤怒的IP扫描程序,例如,扫描200个IP地址所需的时间可能比正常情况下多10倍,并且无法检测到所找到的主机上打开的 * 任何 * 端口。
解决方案是关闭包过滤器,然后删除软件。如this post中所述,停用是通过以下控制台命令完成的:
sudo /Applications/Cisco/Cisco\ AnyConnect\ Socket\ Filter.app/Contents/MacOS/Cisco\ AnyConnect\ Socket\ Filter -deactivateExt
.Cisco安全客户端的路径略有不同:
sudo /Applications/Cisco/Cisco\ Secure\ Client\ -\ Socket\ Filter.app/Contents/MacOS/Cisco\ Secure\ Client\ -\ Socket\ Filter -deactivateExt
一旦这样做,垃圾包过滤器应用程序下的应用程序/思科。VPN连接似乎没有它工作得很好。