我有可用于多个物联网设备的Python代码。我可以同时ssh到其中的许多,而不会出现任何问题(使用pexpect库(。这是在多访问.pool.ThreadPool中完成的。在重新启动我的MacBook之后,在线程池中ping多个主机也很好。ping 55位现场主持人一次,每个人大约需要一秒钟,ping次数正如预期的那样。然而,随着时间的推移,ping代码的工作开始变得很糟糕。Ping时间会增加,直到稍后启动的线程超时为止。第一个启动的线程在合理的ping时间内成功,但ping操作的墙时间非常长——几秒钟后才能返回到100ms以下的ping时间。
我简化了一些测试代码来隔离问题:
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方法都遵循相同的模式。(即使在重新启动后,ping3的行为似乎也很奇怪,但随着时间的推移,情况仍然会变得更糟。(我已经通过WiFi、有线以太网和手机的热点功能尝试过了。我尝试过重新启动所有Python内核,升级Python(通过Anaconda(,升级MacOS(主要和次要(,升级VPN客户端(Cisco(,删除防病毒软件(MS Defender(。一旦它进入这种状态,除了重新启动之外,没有什么能修复它。该模式在所有列出的更新中都会持续存在。
有趣的是,当计算机处于这种状态时,我可以启动一个Docker容器,并使用相同的Python版本运行相同的代码,这非常有效。如果在重新启动后立即关闭Docker Desktop,则既不能修复问题,也不能阻止问题的发生。
我还观察了愤怒的IP扫描仪的操作(设置为使用128个线程(。重新启动后,特定的IP扫描需要14秒。ping问题出现后,同样的扫描需要145秒!
我试着并行地ping路由器30次,问题也出现了,尽管程度要小得多。与其说ping超时,不如说它们对于稍后启动的线程会变得更长。第一个线程在<10ms。最后一个线程以数百毫秒为单位测量ping时间。
更新1:昨晚睡觉前,我用愤怒的IP扫描仪进行了扫描,大约花了15秒。今天早上花了90秒。这个问题似乎是在电脑不用的时候出现的。
更新2:问题再次出现在我离开电脑的时候。这可能与Mac的节能功能有关吗?在最近的这两次事件中,MacBook都连接到了交流电源,因此部分禁用了节能功能(设置中启用了"防止Mac在显示器关闭时自动休眠"(。
这里的问题是Cisco VPN软件。不是客户端本身,而是一些与之配套的辅助扩展,称为数据包过滤器。由于它们是系统网络扩展,因此即使VPN断开连接,它们也处于活动状态。Cisco AnyConnect for MacOS的4.10版中引入(或重新引入(了一个错误,该错误在5.0版(重命名为Cisco Secure Client(中仍然存在。在网络活动期间,它会导致非常高的CPU负载(在我的系统上固定一个处理器内核(,尤其是在主机扫描期间发生的并行操作。性能问题非常严重,例如,愤怒的IP扫描仪扫描200个IP地址的时间可能比正常情况长10倍,并且无法检测到主机上打开的任何端口。
解决方案是关闭数据包过滤器,然后删除软件。如本文所述,停用是通过以下控制台命令完成的:
CCD_ 1。
思科安全客户端的路径略有不同:
sudo /Applications/Cisco/Cisco Secure Client - Socket Filter.app/Contents/MacOS/Cisco Secure Client - Socket Filter -deactivateExt
完成后,在Applications/Cisco下丢弃数据包过滤器应用程序。没有它,VPN连接似乎可以正常工作。