如何创建队列以在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
在静态类中非常耗时。
答案 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.Queue
和get
等put
操作是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-代码对我有用,我希望它也适用于其他人。