python线程不能创建超过800

时间:2016-02-03 12:02:07

标签: python multithreading

下面是我的代码,我对python来说真的很新。从我的下面的代码,我将实际创建多个线程(1000以上)。但在某些时候,近800个线程,我得到一条错误消息说"错误:无法启动新线程"。我确实读过一些关于threadpool的内容。我真的不明白。在我的代码中,我如何实现线程池?或者至少请以简单的方式向我解释

    #!/usr/bin/python


    import threading
    import urllib

    lock = threading.Lock()

    def get_wip_info(query_str):
          try:
              temp = urllib.urlopen(query_str).read()
          except:
              temp = 'ERROR'
          return temp

    def makeURLcall(arg1, arg2, arg3, file_output, dowhat,        result) :

         url1 = "some URL call with args"
         url2 = "some URL call with args"

        if dowhat == "IN" :
             result = get_wip_info(url1)

        elif dowhat == "OUT" :
             result = get_wip_info(url2)

        lock.acquire()

        report = open(file_output, "a")
        report.writelines("%s - %s\n"%(serial, result))
        report.close()

        lock.release()

        return


    testername = "arg1"
    stationcode = "arg2"
    dowhat = "OUT"
    result = "PASS"
    file_source = "sourcefile.txt"
    file_output = "resultfile.txt"

    readfile = open(file_source, "r")
    Data = readfile.readlines()

    threads = []

    for SNs in Data :
        SNs = SNs.strip()
        print SNs
        thread = threading.Thread(target = makeURLcalls, args = (SNs, args1, testername, file_output, dowhat, result))
        thread.start()

        threads.append(thread)

    for thread in threads :
        thread.join()

1 个答案:

答案 0 :(得分:4)

不要实现自己的线程池,使用Python附带的线程池。

在Python 3上,您可以使用concurrent.futures.ThreadPoolExecutor显式使用线程,在Python 2.6及更高版本上,您可以import Pool multiprocessing.dummymultiprocessing API类似,但由线程而不是进程支持。

当然,如果你需要在CPython(参考解释器)中进行CPU绑定工作,你需要使用multiprocessing,而不是multiprocessing.dummy; Python线程适用于I / O绑定工作,但the GIL使它们对CPU绑定工作非常不利。

以下代码用Thread的{​​{1}}替换您对multiprocessing.dummy的明确使用,使用固定数量的工作人员,每个工作人员尽可能快地完成任务,而不是比拥有无限数量的一个工作线程。首先,由于本地I / O可能相当便宜,并且您想要同步输出,我们将使worker任务返回结果数据而不是自己写出来,并让主线程执行写操作到本地磁盘(不需要锁定,以及需要一遍又一遍地打开文件)。这会将Pool更改为:

makeURLcall

现在代替替换显式线程的代码:

# Accept args as a single sequence to ease use of imap_unordered,
# and unpack on first line
def makeURLcall(args):
    arg1, arg2, arg3, dowhat, result = args

    url1 = "some URL call with args"
    url2 = "some URL call with args"

    if dowhat == "IN" :
         result = get_wip_info(url1)
    elif dowhat == "OUT" :
         result = get_wip_info(url2)

    return "%s - %s\n" % (serial, result)