在线程池中执行的 Restrictedpython 代码评估 - 函数被调用两次

Restrictedpython code evaluation executed in thread pool - function invoked twice

我在我的应用程序中使用 restrictedpython 以允许“中等技能用户”开发一些附加代码以作为模块化即时插件执行。

由于某些架构限制,我必须使用线程池来并行执行代码。

这些线程由 10 个一组创建,然后启动并等待加入主执行进程。

我遇到了一些奇怪的问题...有时,我看到 restrictedpython 线程运行了两次!...我环顾四周,我有点惊讶没有人在谈论这个,我不知道我的代码是否有问题,或者 restrictedpython 是否不是线程安全的。

无论如何,你可以看到在我的 RestrictedPythonThread 中我也在编译 restrictedpython 代码之后实现了 Mutex 锁,然后在我有编译代码之前释放了 Mutex 锁。

然后,使用简单的 eval 在没有任何锁的情况下执行编译代码。

这是我的代码:

import logging
import threading
from threading import Thread, Lock

from RestrictedPython import compile_restricted
from RestrictedPython.Eval import default_guarded_getiter, default_guarded_getitem
import os
import psycopg2


def _hook_getattr(obj, attr):
    if obj is os:
        raise RuntimeError('Restricted, cannot use os')
    if obj is psycopg2:
        raise RuntimeError('Restricted, Cannot use psycopg2')
    return getattr(obj, attr)


def _hook_writable(obj):
    if obj.__class__.__name__ == "MY_CLASS_NAME":
        return obj
    if isinstance(obj, dict):
        return obj
    if isinstance(obj, list):
        return obj
    raise RuntimeError('Restricted, Cannot write outside restricted defined class/objects')


def _get_compiled_restricted_python(src):
    return compile_restricted(src, '<string>', 'exec')


_restricted_python_globals = {
    '__metaclass__': type,
    '_getattr_': _hook_getattr,
    '_getiter_': default_guarded_getiter,
    '_write_': _hook_writable,
    '_getitem_': default_guarded_getitem,
    'smart_device': None
}

class RestrictedPythonThread(Thread):
    '''
    A Custom Thread inherited class that manages the restricted python execution using mutex mechanism
    '''

    def __init__(self, dev):
        Thread.__init__(self)
        self.dev = dev

    def run(self):
        global mutex
        mutex.acquire()

        code = _get_compiled_restricted_python(
            self.dev.device_epm.epm)
        code_globals = _restricted_python_globals
        code_globals['dev'] = self.dev
        mutex.release()

        exec(code, code_globals)

在仔细研究之后,我发现使用 python redis 队列问题就消失了...所以这绝对是一个与线程共享内存 space 相关的问题。

也许使用内置的多进程模块就足够了,但我还没有测试它,因为在我的应用程序中我已经使用了 python-rq。