python多线程应用程序挂起

时间:2018-03-23 13:12:18

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

我编写了一个程序,用于对在多线程批量写入条件下执行的mongodb数据库进行基准测试。

问题是程序挂起并且没有完成执行。

我很确定问题是由于将530838条记录写入数据库并使用10个线程一次批量写入50条记录。这会留下38个记录的模数值,但是run方法从队列中获取50条记录,因此当写入530800条记录时进程挂起,并且永远不会写入最后38条记录,因为以下代码永远不会执行

for object in range(50): objects.append(self.queue.get())

我希望程序一次写入50条记录,直到少于50条记录,此时它应该写入队列中的剩余记录,然后在队列中没有记录时退出该记录。

提前致谢:)

import threading
import Queue
import json
from pymongo import MongoClient, InsertOne
import datetime

#Set the number of threads
n_thread = 10
#Create the queue
queue = Queue.Queue()

#Connect to the database
client = MongoClient("mongodb://mydatabase.com")
db = client.threads

class ThreadClass(threading.Thread):

    def __init__(self, queue):
        threading.Thread.__init__(self)
    #Assign thread working with queue
        self.queue = queue


    def run(self):

        while True:
            objects = []

        #Get next 50 objects from queue
            for object in range(50):
                objects.append(self.queue.get())

                #Insert the queued objects into the database           
            db.threads.insert_many(objects)

            #signals to queue job is done
            self.queue.task_done()


#Create number of processes
threads = []

for i in range(n_thread):
    t = ThreadClass(queue)
    t.setDaemon(True)
    #Start thread
    t.start()

#Start timer
starttime = datetime.datetime.now()

#Read json object by object
content = json.load(open("data.txt","r"))
for jsonobj in content:
    #Put object into queue
    queue.put(jsonobj)
#wait on the queue until everything has been processed 
queue.join()

for t in threads:
    t.join()

#Print the total execution time
endtime = datetime.datetime.now()
duration = endtime-starttime
print(divmod(duration.days * 86400 + duration.seconds, 60))

1 个答案:

答案 0 :(得分:0)

docs on Queue.get您可以看到默认设置为block=Truetimeout=None,这会导致在空队列中等待等待下一个可以使用的项目。< / p>

您可以使用get_nowaitget(False)来确保您不会阻止。如果您希望阻止以队列是否有50个项目,是否为空或其他条件为条件,您可以使用Queue.emptyQueue.qsize,但请注意它们不提供竞争条件 - 非阻塞行为的保证......它们仅仅是对block=Falseget一起使用的启发式方法。

这样的事情:

def run(self):

    while True:
        objects = []

        #Get next 50 objects from queue
        block = self.queue.qsize >= 50
        for i in range(50):
            try:
                item = self.queue.get(block=block)
            except Queue.Empty:
                break
            objects.append(item)

        #Insert the queued objects into the database           
        db.threads.insert_many(objects)

        #signals to queue job is done
        self.queue.task_done()

另一种方法是设置timeout并使用try ... except块来捕获引发的任何Empty异常。这样做的好处是你可以决定等待多长时间,而不是试图猜测何时立即返回,但它们是相似的。

另请注意,我将循环变量从object更改为i ...您最有可能避免让循环变量重影全局object类。