创建一个线程python队列?

时间:2018-03-28 14:01:21

标签: python multithreading python-3.x

如何创建队列以在Python中在后台运行任务?

我尝试过asyncio.Queue(),但每当我使用Queue.put(task)时,它会立即启动任务。

适用于在指定时间间隔内从数据库接收未知数量的条目(文件名)的应用程序。我希望用这个backgroundqueue实现的是python应用程序继续运行并不断返回新的文件名。每次应用程序找到新的文件名时,都应该通过创建一个包含(方法(变量))的任务来处理它们。这些任务都应该被抛入一个不断扩展的队列中,该队列自己运行任务。这是代码。

class DatabaseHandler:
def __init__(self):
    try:
        self.cnx = mysql.connector.connect(user='root', password='', host='127.0.0.1', database='mydb')
        self.cnx.autocommit = True
        self.q = asyncio.Queue()
    except mysql.connector.Error as err:
        if err.errno == errorcode.ER_ACCESS_DENIED_ERROR:
            print("Something is wrong with your user name or password")
        elif err.errno == errorcode.ER_BAD_DB_ERROR:
            print("Database does not exist")
        else:
            print(err)
    self.get_new_entries(30.0)

def get_new_entries(self, delay):
    start_time = t.time()
    while True:
        current_time = datetime.datetime.now() - datetime.timedelta(seconds=delay)
        current_time = current_time.strftime("%Y-%m-%d %H:%M:%S")
        data = current_time
        print(current_time)
        self.select_latest_entries(data)
        print("###################")
        t.sleep(delay - ((t.time() - start_time) % delay))

def select_latest_entries(self, input_data):
    query = """SELECT FILE_NAME FROM `added_files` WHERE CREATION_TIME > %s"""
    cursor = self.cnx.cursor()
    cursor.execute(query, (input_data,))
    for file_name in cursor.fetchall():
        file_name_string = ''.join(file_name)
        self.q.put(self.handle_new_file_names(file_name_string))
    cursor.close()

def handle_new_file_names(self, filename):
    create_new_npy_files(filename)
    self.update_entry(filename)

def update_entry(self, filename):
    print(filename)
    query = """UPDATE `added_files` SET NPY_CREATED_AT=NOW(), DELETED=1 WHERE FILE_NAME=%s"""
    update_cursor = self.cnx.cursor()
    self.cnx.commit()
    update_cursor.execute(query, (filename,))
    update_cursor.close()

正如我所说,这将立即执行任务。

create_new_npy_files在静态类中非常耗时。

2 个答案:

答案 0 :(得分:2)

此表达式存在两个问题:

self.q.put(self.handle_new_file_names(file_name_string))

首先,它实际上是调用 handle_new_file_names方法并将其结果排入队列。这不是asyncio.Queue特有的,它是函数调用在Python(以及大多数主流语言)中的工作方式。以上相当于:

_tmp = self.handle_new_file_names(file_name_string)
self.q.put(_tmp)

第二个问题是,asyncio.Queuegetput操作是coroutines,因此您必须等待它们。

如果要将可调用队列入队列,可以使用lambda

await self.q.put(lambda: self.handle_new_file_names(file_name_string))

但是由于队列的使用者在你的控制之下,你可以简单地将文件名排入队列,如@dirn所示:

await self.q.put(file_name_string)

队列的使用者将使用await self.q.get()来读取文件名,并在每个文件名上调用self.handle_new_file_names()

如果您打算使用asyncio,请考虑涵盖基础知识的reading a tutorial,并切换到asyncio compliant数据库连接器,以便数据库查询与asyncio事件循环一起播放。

答案 1 :(得分:1)

对于将来看到这一点的人。我标记为接受的答案是如何解决问题的解释。我会写下一些我用来创建我想要的代码。也就是说,应该在后台运行的任务。你走了。

from multiprocessing import Queue
import threading

class ThisClass
    def __init__(self):
        self.q = Queue()
        self.worker = threading.Thread(target=self._consume_queue)
        self.worker.start()
        self.run()

创建的队列不是任务的队列,而是您要处理的变量的队列。

def run(self):
    for i in range(100):
        self.q.put(i)

然后是_consume_queue(),当有项目时,它会消耗队列中的项目:

def _consume_queue(self):
    while True:
        number = self.q.get()
        # the logic you want to use per number.

似乎self.q.get()等待新条目,即使没有。

上面的-simplified-代码对我有用,我希望它也适用于其他人。