我有一个函数,它接受 html 字符串,通过删除停止词来清理它,然后计算用户确定的搜索字符串中单词出现的次数:
def clean_text(string, search_term):
"""
This function removes stop words and non alphanumeric characters from a string and counts the number of times each word in a specified search term appears in the string.
:param string: the string to clean
:param search_term:
"""
stop_words = set(stopwords.words('english'))
word_tokens = word_tokenize(string)
alpha_string = [word.lower() for word in word_tokens if word.isalpha()]
cleaned_string = [word.lower() for word in alpha_string if word.lower() not in stop_words]
c = Counter(cleaned_string)
total_freq = np.sum([c[i] for i in search_term.lower().split()])
if total_freq == 0:
return (0, 0)
else:
return " ".join(cleaned_string), total_freq
我正在尝试使用 python 的 asyncio 将其转换为异步函数。我有以下代码:
async def clean_text_async(string, search_term):
"""
This function removes stop words and non alphanumeric characters from a string and counts the number of times each word in a specified search term appears in the string.
:param string: the string to clean
:param search_term:
"""
stop_words = set(stopwords.words('english'))
word_tokens = word_tokenize(string)
alpha_string = [word.lower() for word in word_tokens if word.isalpha()]
cleaned_string = [word.lower() for word in alpha_string if word.lower() not in stop_words]
c = Counter(cleaned_string)
total_freq = np.sum([c[i] for i in search_term.lower().split()])
if total_freq == 0:
return (0, 0)
else:
return " ".join(cleaned_string), total_freq
async def async_main_html(df_html):
clean_text_tasks = []
for html in df_html['html']:
task = asyncio.create_task(clean_text_async(string = html, search_term = search_term))
clean_text_tasks.append(task)
results = await asyncio.gather(*clean_text_tasks)
return results
cleaned_text = await async_main_html(df_html)
代码可以使用上述命令运行并运行,但我不认为它是异步运行的,因为使用 async_main_html 和 clean_text 运行该函数需要相同的时间。
我做错了什么吗?
您没有了解异步编程的作用 - 事实上,它对此代码根本没有任何好处!
异步代码是单线程的,当一个任务必须等待外部源(文件系统、数据库、HTTP API 等)提供数据时,只允许代码并发运行。此时它将使用
await
语句(或等效语句)获取数据,虽然该数据尚未准备好,但其他任务有机会运行。
您的代码只是进行处理 - 使用
await
语句是没有意义的 - 因此首先异步运行它是没有意义的。
但是,在一种情况下,它可能会受益匪浅:如果此处理是作为 API 中处理请求的一部分进行的,并且可能需要同时处理其中多个请求,则可以使用 asyncio在其他线程中运行某些 CPU 密集型处理。例如,由于 Python 中的正则表达式引擎在本机代码中运行,因此它将释放 GIL,从而在某种程度上允许正则表达式在后台并行运行,并且您可以获得一些改进 - 如果您在以下位置发出其中几个任务一次。然而,完成单个任务的时间将保持不变。
如果您选择以这种方式重新构建代码,而不是像您所做的那样将
clean_text
更改为协同例程函数,只需按原样运行(同步,使用普通的 def
而不是 async def
),但可以使用 asyncio.create_task(asyncio.run_in_executor(None, clean_text, *args))
调用从异步代码中调用它。
如果这在某种程度上有效,您可能需要微调自定义“执行器”,而不是使用带有 None 的默认“执行器”来提取一些额外的性能。