同时,随着计算机正常运行时间的增加,ping 代码会变慢并中断。这是怎么回事?



我有可用于多个物联网设备的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连接似乎可以正常工作。

相关内容

最新更新