将功能置于后台

时间:2018-11-19 04:37:52

标签: python python-3.x python-asyncio

我具有以下功能:

def update_contacts(data):
    '''
    Update a user's contacts from Google: to be run as a background task.
    '''
    from users.google_oauth import GoogleOauthClient
    email = data['email']
    access_token = data['access_token']
    g = GoogleOauthClient()
    contacts = g.get_all_contacts(email=email, access_token=access_token, insert=True)
    log.info('Fetched and updated %s contacts' % (len(contacts)))

我正在寻找创建一个通用函数,该函数将在后台运行其他函数,例如上面的函数。这是我到目前为止的内容:

def run_in_background(function):
    '''
    I want this to be able to receive a normal function call,
    such as `update_contacts(data)` or get_first_name('tom')
    '''

    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    loop.run_in_executor(None, function, data)

然后我会将此传递称为:

data={'email': email,'access_token': g.tokens['access_token']}
run_in_background (
    update_contacts(data)
)

问题是,我认为它将首先运行update_contacts函数,并且实际上不会做任何异步操作。我如何正确编写和调用run_in_background函数?

也许我需要使用类似partial之类的方法来传递函数,而无需实际调用它,直到函数执行为止?

3 个答案:

答案 0 :(得分:3)

正如其他指出的那样,表达式run_in_background(update_contacts(data))在调用update_contacts(data)之前将对run_in_background求值。无论如何实现run_in_background,都必须向其传递 function

您要查找的run_in_background函数已经存在,它是ThreadPoolExecutor上的submit方法:

with ThreadPoolExecutor() as executor:
    data = { ... }
    future = executor.submit(update_contacts, data)
    # ... the function now runs in a background thread,
    # and you can do other things here ...

您可以对返回的Future对象使用诸如done()result()之类的方法来测试提交的任务是否已完成或获取函数的结果。这比手动启动线程更可取,因为执行器可以通过维护线程池来支持大量后台任务。还有一个执行器使用multiprocessing提供真正的并行性。

所有这些都完全独立于asyncio库及其run_in_executor方法,该方法用于将阻塞代码与专门为asyncio编写的代码(您似乎没有)连接起来。

答案 1 :(得分:0)

不确定asyncio。但是,我相信您也可以使用线程, 然后可以如下修改您的函数:

def background_function(func, params):
    t1 = threading.Thread(target=func, args = params)
    t1.start()

通话示例:

 def do_something(num):
   print('printing' + num + 'times')

def call_do_domething():
   background_function(do_something, args = [1000])

答案 2 :(得分:-1)

如果您调用run_in_background (update_contacts(data)),则意味着您已经调用了函数update_contacts(data)。但是,您只应像这样传递函数及其参数:

run_in_background(update_contacts, args=(data,))

然后相应地更改您的run_in_background函数

def run_in_background(function, args=()):
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    loop.run_in_executor(None, function, *args)