用于字符串列表的Python 2.7多处理池?

用于字符串列表的Python 2.7多处理池?,python,python-2.7,python-multiprocessing,Python,Python 2.7,Python Multiprocessing,我是Python新手(免责声明:我是编程新手,已经在线阅读Python两周了),我已经编写了一个简单的多处理脚本,应该允许我同时使用四个子流程。我使用了一个全局变量(是的,我现在更清楚了)来跟踪一次运行了多少个进程。启动一个新流程,一个一个递增;结束一个过程,递减一。这是混乱的,但我只专注于让多进程工作,它确实做到了 到目前为止,我已经做了相当于: processes = 0 def function(value) global processes do stuff to va

我是Python新手(免责声明:我是编程新手,已经在线阅读Python两周了),我已经编写了一个简单的多处理脚本,应该允许我同时使用四个子流程。我使用了一个全局变量(是的,我现在更清楚了)来跟踪一次运行了多少个进程。启动一个新流程,一个一个递增;结束一个过程,递减一。这是混乱的,但我只专注于让多进程工作,它确实做到了

到目前为止,我已经做了相当于:

processes = 0

def function(value)
    global processes
    do stuff to value
    processes-=1

While read line
    if processes < 4
        processes+=1
        create a new subprocess - function(line)
进程=0
def函数(值)
全球进程
做有价值的事
进程-=1
读行时
如果进程小于4
进程+=1
创建新的子流程-函数(行)
1:我需要以比全球跟踪更好的方式跟踪流程。我在python中看到了“池”的一些用途,即有4个工人,但我在这方面很失败。我喜欢游泳池的想法,但我不知道如何将列表的每一行传递给下一个工人。想法

2:在一般原则上,为什么我的全局var递减率不起作用?我知道这很难看,但我至少预期它会难看和成功

3:我知道我不会在编辑之前锁定var,我想补充一点,一旦递减操作正常工作,就会锁定var

抱歉,如果这是可怕的伪代码,但我想你可以看到要点。以下是您想要深入了解的真实代码:

MAX_THREADS = 4
CURRENT_THREADS = 0
MAX_LOAD = 8

# Iterate through all users in the userlist and call the funWork function on each user
def funReader(filename):

    # I defined the logger in detail above, I skipped about 200 lines of code to get it slimmed down
    logger.info("Starting 'move' function for file \"{0}\"...".format(filename))

    # Read in the entire user list file
    file = open(filename, 'r')
    lines = file.read()
    file.close()

    for line in lines:
        user = line.rstrip()
        funControl(user)

# Accept a username and query system load and current funWork thread count; decide when to start next thread
def funControl(user):

    # Global variables that control whether a new thread starts
    global MAX_THREADS
    global CURRENT_THREADS
    global MAX_LOAD

    # Decide whether to start a new subprocess of funWork for the current user
    print
    logger.info("Trying to start a new thread for user {0}".format(user))
    sysLoad = os.getloadavg()[1]

    logger.info("The current threads before starting a new loop are: {0}.".format(CURRENT_THREADS))
    if CURRENT_THREADS < MAX_THREADS:
        if sysLoad < MAX_LOAD:
            CURRENT_THREADS+=1
            logger.info("Starting a new thread for user {0}.".format(user))
            p = Process(target=funWork, args=(user,))
            p.start()
        else:
            print "Max Load is {0}".format(MAX_LOAD)
            logger.info("System load is too high ({0}), process delayed for four minutes.".format(sysLoad))
            time.sleep(240)
            funControl(user)
    else:
        logger.info("There are already {0} threads running, user {1} delayed for ten minutes.".format(CURRENT_THREADS, user))
        time.sleep(600)
        funControl(user)

# Actually do the work for one user
def funWork(user):

    global CURRENT_THREADS

    for x in range (0,10):
        logger.info("Processing user {0}.".format(user))
        time.sleep(1)
    CURRENT_THREADS-=1
MAX_THREADS=4
当前线程=0
最大载荷=8
#遍历userlist中的所有用户,并对每个用户调用funWork函数
def funReader(文件名):
#我在上面详细定义了记录器,我跳过了大约200行代码来精简它
logger.info(“启动文件\“{0}\”的“移动”函数…”。格式(文件名))
#读入整个用户列表文件
文件=打开(文件名“r”)
lines=file.read()
file.close()文件
对于行中的行:
user=line.rstrip()
funControl(用户)
#接受用户名并查询系统负载和当前funWork线程数;决定何时开始下一个线程
def funControl(用户):
#控制新线程是否启动的全局变量
全局最大线程数
全局当前线程
全局最大载荷
#决定是否为当前用户启动funWork的新子流程
打印
info(“尝试为用户{0}启动新线程”。格式化(用户))
sysLoad=os.getloadavg()[1]
info(“启动新循环之前的当前线程是:{0}。”.format(当前_线程))
如果当前线程<最大线程:
如果系统负载<最大负载:
当前线程数+=1
info(“为用户{0}启动新线程。”.format(user))
p=进程(目标=工作,参数=(用户,))
p、 开始()
其他:
打印“最大负载为{0}”。格式(最大负载)
info(“系统负载过高({0}),进程延迟四分钟。”.format(sysLoad))
时间。睡眠(240)
funControl(用户)
其他:
info(“已经有{0}个线程在运行,用户{1}延迟了十分钟。”.format(当前线程,用户))
时间。睡眠(600)
funControl(用户)
#实际上为一个用户做这项工作
def funWork(用户):
全局当前线程
对于范围(0,10)内的x:
logger.info(“正在处理用户{0}.”格式(用户))
时间。睡眠(1)
当前线程-=1
最后:您看到的任何错误都可能是转录错误,因为代码在工作的服务器上执行时没有bug。然而,您看到的任何可怕的编码实践都完全是我的

提前谢谢

这个怎么样:(未测试)


有什么特别的原因不能只使用multiprocessing.Pool来做你想做的事情吗?(如果要考虑平均负载,只需让进程池创建人员检查它并调节自己;这似乎是一个奇怪的要求,可能有更好的解决方案——renice、cgroups或其他)。是的,有timday,原因是我不知道如何将每一行传递到处理池。你介意我再多说一点我该怎么做吗?我已经阅读了大量关于4个工作池的示例,但我不知道如何将文件中的每一行传递给新进程。编辑:为了给我一个快速的答案,我试着点击回车键,输入一行“谢谢”,但很明显,这只是提交了这篇文章。Aaron提供了一个答案,说明了如何使用pool.map(这正是我在这类事情上使用的)。请注意,池在创建池时只创建一次工作进程池,因为这比为处理的每一行创建一个新进程要高效得多。使用游泳池的最佳参考。亚伦,我正在测试你的建议。泳池上的医生很棒,谢谢!关于线程与进程:我开始认为我需要线程,因为我的工作人员对我说“线程”。在做了我自己的研究之后,我意识到我需要进程,但我的原始代码在我了解更多之前仍然说线程。我也在修复它,我很欣赏它的与众不同!没问题!事实上,我已经通过手动创建工作进程池创建了自己的处理池类,不过默认实现通常已经足够好了。我只是想为我的处理池增加一点额外的功能(估计完成作业的剩余时间、剩余完成作业的确切数量等等)。祝你的项目好运!
MAX_PROCS = 4

# Actually do the work for one user
def funWork(user):

    for x in range (0,10):
        logger.info("Processing user {0}.".format(user))
        time.sleep(1)
    return

# Iterate through all users in the userlist and call the funWork function on each user
def funReader(filename):

    # I defined the logger in detail above, I skipped about 200 lines of code to get it slimmed down
    logger.info("Starting 'move' function for file \"{0}\"...".format(filename))

    # Read in the entire user list file
    file = open(filename, 'r')
    lines = file.read()
    file.close()

    work = []
    for line in lines:
        user = line.rstrip()
        work.append(user)
    pool = multiprocessing.Pool(processes=MAX_PROCS)  #threads are different from processes...
    return pool.map(funWork, work)