在xlwing中始终使用异步UDF来更新单元格有意义吗?

时间:2018-12-17 12:57:41

标签: python excel xlwings

对于返回将要写入Excel单元格的结果的xlwings UDF,始终使UDF异步以使Excel在处理UDF时不冻结,是否有意义?

有没有不使用异步UDF更好的情况?

https://docs.xlwings.org/en/stable/udfs.html#asynchronous-udfs

我正在使用Excel 2016和Windows 10

3 个答案:

答案 0 :(得分:2)

我认为真正的问题是何时使用异步UDF。不管我们是否在xlwings中,这个问题的答案都是相同的。我将引用MSFT

  

某些用户定义的函数必须等待外部资源。当他们等待时,Excel计算线程被阻止。用户定义的函数可以异步运行。在用户定义的函数等待时,这将释放计算线程以运行其他计算。

在Excel中广泛使用异步函数将效率低下,但我还怀疑它可能会导致错误和错误的应用程序状态。这是基于我的经验得出的观点,但未经官方证实,因此我希望能有专家的意见。

答案 1 :(得分:1)

如果您需要与Excel一起正常工作的异步函数,而不是稍后再使用COM将值写回到Excel,则应使用Excel的异步函数或RTD(实时数据)函数。 AFAIK,xlwings都不使用这些。

Excel的异步功能与以后使用后台线程将结果写回到Excel的方式不同。它们在Excel计算周期内运行,但是允许计算同时运行,因此,例如,其他计算不会在等待IO的情况下被阻止。

如果您的函数运行时间很长,并且不想等待它返回,那么最好使用RTD函数,该函数在结果准备好后会更新一次。

PyXLL(https://www.pyxll.com)支持异步和RTD功能。

https://www.pyxll.com/docs/userguide/udfs.html#asynchronous-functions https://www.pyxll.com/docs/userguide/rtd.html

另一个选择是使用线程安全功能。它们在Excel中的后台线程池中运行。如果您具有可以并发运行的功能(即,它们释放GIL来执行IO或CPU密集型任务),那么这是提高工作表性能的简单方法。

要使用PyXLL将功能标记为线程安全,只需在注册功能时指定“ thread_safe = True”即可,例如:

from pyxll import xl_func

@xl_func(thread_safe=True)
def my_thread_safe_function():
    pass

答案 2 :(得分:1)

您可以使用xlOil(免责声明:我写过)来执行此操作。 xlOil同时使用Excel的本机异步和RTD服务器支持异步功能。 Python插件的文档位于:https://xloil.readthedocs.io/en/latest/xlOil_Python/index.html

以下python模块声明了一个异步Excel函数longRunningFunction

import xloil
import asyncio

@xloil.func
async def longRunningFunction(returnVal, waitTime:int):
    await asyncio.sleep(waitTime)
    return returnVal

默认情况下,xlOil使用RTD技术来完成这项工作,因为Excel的本机异步实际上与UI不异步。这意味着,如果您通过以任何方式与Excel交互来停止计算,则所有本机异步函数都将被取消。

RTD与UI异步,但是有一些开销,因此仅应在需要的地方使用。它还需要启用自动计算才能按预期工作,即,值在返回时将出现在Excel中。 (尽管您可以在UDF末尾使用Application.Calculatexloil.run_later()添加延迟的调用,以避免此要求)。 xlOil Docs中讨论了相对优势。

xlOil使用python的asyncio库,因此需要一个可等待的函数。如果您要调用的python代码不异步,则可以始终在新进程中运行它,然后使用concurrent.futures.ProcessPoolExecutor等待该进程。