我们想制作一个电子商务应用程序,团队是python开发人员,但不使用python web框架(Django / Flask ......),因为我们发现Tornado因其简单性而非常出色,我们给了他很大的比例。
但问题是,Tornado是单线程的,应用程序将使用散列(登录)和图像处理(缩略图生成)。可以ThreadPoolExecutor
扮演像Apache这样的多线程服务器的角色,如本例所示吗?
from concurrent.futures import ThreadPoolExecutor
from tornado import gen
from tornado.process import cpu_count
import bcrypt
pool = ThreadPoolExecutor(cpu_count())
@gen.coroutine
def create_user(name, password):
hashed_pw = yield pool.submit(bcrypt.hashpw, password, bcrypt.gensalt())
yield save_user(name, hashed_pw)
@gen.coroutine
def login(name, password):
user = yield load_user(name)
match = yield pool.submit(bcrypt.checkpw, password, user.hashed_pw)
if not match:
raise IncorrectPasswordError()
因此,Tornado将散列工作发送到另一个线程,以释放自己并能够接收其他请求。这种方法会起作用吗?
注意:还有一个涉及负载均衡器的解决方案,但团队现在不想追求这个解决方案。
答案 0 :(得分:2)
是的,ThreadPoolExecutor
在这里运作良好。看起来hashpw
和checkpw
都会在CPU操作过程中释放GIL:
bcrypt_hashpw(PyObject *self, PyObject *args, PyObject *kw_args)
{
...
Py_BEGIN_ALLOW_THREADS;
ret = pybc_bcrypt(password_copy, salt_copy, hashed, sizeof(hashed));
Py_END_ALLOW_THREADS;
...
这意味着您可以将该工作转移到一个CPU,同时使用另一个CPU处理传入的请求。
请记住,如果你需要做一些其他运行pure-Python的CPU绑定操作(意味着GIL没有发布),你需要使用ProcessPoolExecutor
来避免服用表现受到打击。