在线程池中执行的 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。
我在我的应用程序中使用 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。