在一个线程中执行Twisted reactor.run()?

use*_*395 6 python ubuntu cocoa twisted

我正在尝试使用Python库来使用Objective-C中的Ubutu One API.这是我的源代码:https: //github.com/JoseExposito/U1-Finder-Plugin/blob/master/U1FinderLib/U1FinderLib.py

我需要对API进行多次调用,因此我需要让我的reactor运行一次而不是运行它并停止它,就像在Ubuntu One文档的示例中一样:https: //one.ubuntu.com/developer /文件/ store_files/syncdaemontool

因为不可能运行两次反应器...而且我需要在一个线程中执行reactor.run(),因为我无法阻止使用该库的应用程序!

有可能这样做吗?我无法在一个线程中运行反应器并调用Ubuntu One API同步.

编辑:

我正在使用这个简单的源代码来测试这个想法:

#!/usr/bin/env python
import objc
import thread
import os
import time
from   twisted.internet import reactor, defer
from   ubuntuone.platform.tools import (SyncDaemonTool, is_already_running)
from   threading import Thread
NSObject = objc.lookUpClass('NSObject')

##
# Variable to get the result of the calls to the Sync Daemon.
# The result is a JSON string stored in returned_value[0].
returned_value = ['']

##
# Objective-C facade to the methods of the U1FinderLib.
class U1FinderLib(NSObject):

    def init(self):
        self = super(U1FinderLib, self).init()
        self.sync_daemon_tool = SyncDaemonTool(None)
        Thread(target=reactor.run, args=(False,)).start()
        return self

    @objc.typedSelector('@@:')
    def volumeList(self):
        print "Begin volumeList"
        reactor.callLater(0, run_command, "volume_list", [], self.sync_daemon_tool)
        print "End volumeList"
        return returned_value[0]

##
# Auxiliar functions to call to the sync daemon.
@defer.inlineCallbacks
def run_command(action, params, sync_daemon_tool):
    print "run_command"
    running = yield is_already_running()
    print "After is_already_running"
    try:
        if not running:
            returned_value[0] = '{ type:"error" reason:"Sync Daemon is not running" }'
        else:
            print "Before run_action"
            yield run_action(action, params, sync_daemon_tool)
            print "After run_action"
    except Exception, e:
        returned_value[0] = '{ type:"error" reason:"Exception: %s" }' % e

@defer.inlineCallbacks
def run_action(action, params, sync_daemon_tool):
    if action == "volume_list":
        d = sync_daemon_tool.get_folders()
        returned_value[0] = yield d.addCallback(lambda r: volume_list(r))

# Volume List
def volume_list(folders):
    volumes_json = '{ type:"volume_list" volumes: { \n\t{ volume:"' + os.path.expanduser('~/Ubuntu One') + '" subscribed:"YES" }'
    for folder in folders:
        volumes_json += ',\n\t{ volume:"' + folder['path'] + '" subscribed:"' + ('YES' if bool(folder['subscribed']) else 'NO') + '" }'
    volumes_json += '\n} }'
    return volumes_json

if __name__ == '__main__':
    py = U1FinderLib.alloc().init()
    print py.volumeList()
    print "EXIT"
Run Code Online (Sandbox Code Playgroud)

这是该计划的输出:

Begin volumeList
End volumeList

EXIT
Run Code Online (Sandbox Code Playgroud)

问题是永远不会调用"run_command"函数

Jea*_*one 16

您应该使用与要使用它的应用程序集成的reactor,而不是在线程中运行reactor.

例如,您可能希望使用CoreFoundation反应器(因为您的应用程序使用Obj-C并且名称中包含"Finder").

如果你真的不能这样做(例如,如果Ubuntu One需要一个不同的反应器 - 我不知道是否是这种情况),那么你可能可以在一个线程中运行该反应器.大多数反应堆确实支持这一点,但如果Ubuntu One需要特定的反应堆,那么该反应堆可能不支持线程使用.

你没有真正解释当你尝试在线程中运行reactor时遇到的问题,所以我无法理解为什么它不起作用.但是,这样做应该很容易.只是:

from twisted.internet import reactor
from threading import Thread

Thread(target=reactor.run, args=(False,)).start()
Run Code Online (Sandbox Code Playgroud)

请记住,一旦选择在线程中运行reactor,您只能线程中使用Twisted API .

如果这不起作用,请提供有关它在您的问题中不起作用的更多详细信息.

  • 这些API都不是线程安全的.在非反应器线程中,使用`reactor.callFromThread`来安排在reactor线程中调用的函数. (3认同)