多处理超时?

时间:2017-12-08 10:12:33

标签: python multithreading python-3.x python-multiprocessing

此代码ping各种机器。你可以帮我修改一下这段代码吗?如果一个ping过程挂起超过7秒,它会关闭并返回一些标志吗?

(我想从使用WMI的机器中提取各种数据。为此我会将ping功能更改为其他内容。问题是在某些机器上WMI已损坏且数据拉动过程无限期挂起。需要超时。 )

import multiprocessing.dummy
import subprocess
import numpy as np
import time

start_time = time.time()

def ping(ipadd):
    try:
        response = subprocess.check_output(['ping', ipadd])
        return True
    except subprocess.CalledProcessError as e:
        return False
#print(ping('10.25.59.20'))
machine_names = \
'''
ya.ru
microsoft.com
www.google.com
www.amazon.com
www.nasa.com
'''.split()

np_machine_names = np.array(machine_names)
p = multiprocessing.dummy.Pool(7)
ping_status = p.map(ping, machine_names)
np_ping_status = np.fromiter(ping_status, dtype=bool)
print(*np_machine_names[np_ping_status], sep = '\n')


run_time = time.time() - start_time
print(f'Runtime: {run_time:.0f}')

更新: 虽然我很欣赏有关向子进程添加超时的提示,但问题仍然存在。如何关闭挂起的功能?假设我已经改变ping操作从机器中提取WMI数据(这个从Windows机器中提取已安装软件的列表)。没有子进程来设置计时器:

#pip install pypiwin32
import win32com.client 
strComputer = "." 
objWMIService = win32com.client.Dispatch("WbemScripting.SWbemLocator") 
objSWbemServices = objWMIService.ConnectServer(strComputer,"root\cimv2") 
colItems = objSWbemServices.ExecQuery("Select * from Win32_Product") 
for objItem in colItems: 
    print( "Caption: ", objItem.Caption )

3 个答案:

答案 0 :(得分:1)

使用asyncio它自3.5.4以来在python中可用

https://docs.python.org/3/library/asyncio-task.html

答案 1 :(得分:1)

在使用Popen模块时,

subprocess是默认选择。它允许您创建一个进程,然后使用指定的超时读取其stdout和stderr:

def ping(ipadd):
    process = subprocess.Popen(['ping', ipadd])
    try:
        response, stderr_response = process.communicate(timeout=10)
        return True
    except subprocess.TimeoutExpired:
        return False
    finally:
        process.kill()

另外,请注意linux或osx上的ping可能永远不会退出并继续ping,因此这些操作系统将返回false:

>>> ping('127.0.0.1')
PING 127.0.0.1 (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.058 ms
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.033 ms
...
64 bytes from 127.0.0.1: icmp_seq=8 ttl=64 time=0.064 ms
64 bytes from 127.0.0.1: icmp_seq=9 ttl=64 time=0.031 ms
False

答案 2 :(得分:1)

有多种方法可以解决长时间执行的问题。每种方式都有其优点和缺点。

<强>的API

如前所述,最简单的方法是依赖API超时。 subprocesssocketrequests等模块在其API中公开超时参数。

这是可行的首选方法。

<强>线程

长时间运行/挂起逻辑在单独的线程中执行。主循环可以继续不受干扰并忽略挂起的执行。

import threading

TIMEOUT = 60

def hanging_function():
    hang_here()

thread = threading.Tread(target=hanging_function)
thread.daemon = True
thread.start()

thread.join(TIMEOUT)
if thread.is_alive():
    print("Function is hanging!")

此方法的一个问题是挂起的线程将继续在后台消耗资源中执行。

另一个限制是由于线程共享内存。如果您的功能发生严重崩溃,也可能会影响您的主要执行。

<强>过程

我最喜欢的方法是使用multiprocessing工具在单独的流程中执行有问题的逻辑。由于进程不共享内存,因此在有问题的函数中发生的任何事情仍然局限于您可以在任何时间点终止的子进程。

import multiprocessing

TIMEOUT = 60

def hanging_function():
    hang_here()

process = multiprocessing.Process(target=hanging_function)
process.daemon = True
process.start()

process.join(TIMEOUT)
if process.is_alive():
    print("Function is hanging!")
    process.terminate()
    print("Kidding, just terminated!")

pebble库是建立在这个原则之上的。允许轻松分离有问题的代码并处理故障和灾难。

使用流程的缺点是它们比其他两种方法重一点。此外,由于进程之间的内存是隔离的,因此共享数据会有点复杂。