python创建进程损耗_Python fork:如果进程消耗超过50%,则“无法...

你面临的问题并不是真的与Python有关,也不是你可以用Python单独改变的东西.如评论中的mbrig所建议的那样,在前面开始分叉过程(执行程序)实际上似乎是这种情况的最佳和最干净的选择.

无论是否是Python,您正在处理Linux(或类似系统)如何创建新流程.您的父进程首先调用fork(2),它将创建一个新的子进程作为其自身的副本.它实际上并没有在那时将其自身复制到其他地方(它使用写时复制),但它会检查是否有足够的空间可用,如果没有将errno设置为12则失败:ENOMEM – >你看到的OSError异常.

是的,允许VMS过度使用内存可以抑制弹出的错误…并且如果你在孩子中执行新程序(这也会最终变小).它不必导致任何立即失败.但这听起来似乎可能会在未来的道路上继续解决问题.

增长记忆(添加交换).推动限制,只要运行过程的两倍仍然适合可用内存,fork就可以成功.通过后续执行,交换甚至不需要被利用.

似乎还有一个选择,但看起来……很脏.还有另一个系统调用vfork(),它创建一个新进程,该进程最初与其父进程共享内存,该进程在该点暂停执行.这个新创建的子进程只能设置vfork返回的变量,它可以_exit或exec.因此,它不是通过任何Python接口公开的,如果你尝试(我做)使用ctypes直接将它加载到Python中,它会段错误(我认为因为Python仍会做其他事情,然后只是在vfork之后和之前提到的那三个动作可以在孩子身上执行其他事情).

也就是说,你可以将整个vfork和exec委托给你加载的共享对象.作为一个非常粗略的概念证明,我做到了这一点:

#include

#include

#include

#include

#include

char run(char * const arg[]) {

pid_t child;

int wstatus;

char ret_val = -1;

child = vfork();

if (child < 0) {

printf("run: Failed to fork: %i

", errno);

} else if (child == 0) {

printf("arg: %s

", arg[0]);

execv(arg[0], arg);

_exit(-1);

} else {

child = waitpid(child, &wstatus, 0);

if (WIFEXITED(wstatus))

ret_val = WEXITSTATUS(wstatus);

}

return ret_val;

}

我已经按照以下方式修改了您的示例代码(更改的大部分内容是替换subprocess.call):

import ctypes

import os

import psutil

pid = os.getpid()

this_proc = psutil.Process(pid)

MAX_MEM = int(psutil.virtual_memory().free*1E-9) # in GB

def consume_memory(size):

""" Size in GB """

memory_consumer = []

while get_mem_usage() < size:

memory_consumer.append(" "*1000000) # Adding ~1MB

return(memory_consumer)

def get_mem_usage():

return(this_proc.memory_info()[0]/2.**30)

def get_free_mem():

return(psutil.virtual_memory().free/2.**30)

if __name__ == "__main__":

forker = ctypes.CDLL("forker.so", use_errno=True)

for i in range(1, MAX_MEM):

consumer = consume_memory(i)

mem_usage = get_mem_usage()

print("

## Memory usage %d/%d GB (%2d%%) ##" % (int(mem_usage),

MAX_MEM, int(mem_usage*100/MAX_MEM)))

try:

cmd = [b"/bin/echo", b"[OK] Fork worked."]

c_cmd = (ctypes.c_char_p * (len(cmd) + 1))()

c_cmd[:] = cmd + [None]

ret = forker.run(c_cmd)

errno = ctypes.get_errno()

if errno:

raise OSError(errno, os.strerror(errno))

except OSError as e:

print("[ERROR] Fork failed. Got OSError.")

print(e)

del consumer

有了这个,我仍然可以在报告填充的3/4可用内存中分叉.

理论上它可以全部写成“正确”并且很好地包装好以便很好地集成Python代码,但它似乎是一个额外的选择.我还是会回到执行程序进程.

我只是简单地扫描了concurrent.futures.process模块??,但是一旦它产生了一个工作进程,它似乎在完成之前就没有破坏它,所以滥用现有的ProcessPoolExecutor可能是一个快速而便宜的选择.我已将这些添加到脚本顶部(主要部分):

def nop():

pass

executor = concurrent.futures.ProcessPoolExecutor(max_workers=1)

executor.submit(nop) # start a worker process in the pool

然后将subprocess.call提交给它:

proc = executor.submit(subprocess.call, ['echo', '[OK] Fork worked.'])

proc.result() # can also collect the return value

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值