线程与异步图像处理?
我有一个Python函数,它在被访问时会生成一张图片。我可以选择在收到HTTP请求时直接调用这个函数,或者使用Gearman异步处理。请求量很大。
那么,哪种方式更好呢:
- 内联 - 直接生成图片,这样会导致一次生成很多图片
- 异步 - 将任务放入队列(使用Gearman),然后在工作进程中生成图片
哪种选择更好呢?
在这里,“更好”意味着最佳的速度/负载组合。生成图片的例子只是个象征,这种情况也适用于数据库连接和其他事情。
2 个回答
如果你的程序在解释器中主要依赖CPU,那么即使有足够的处理器来运行多个线程,启动多个线程反而会让结果变慢。这是因为全局解释器锁(GIL)只允许一个线程在解释器中同时运行。
如果大部分工作是在C语言库中完成的,那么可能就不会有这个锁的限制,这样你就可以有效地使用多个线程。
如果你自己在创建线程,要注意不要创建太多线程,比如一次创建1万个线程就会出问题。因此,你需要设置一个工作队列,让线程从中读取任务,而不是简单地在循环中不断创建线程。
如果是我在做这件事,我会直接使用标准的多进程模块。
我有一个Python函数,它在被访问时会生成一张图片。我可以在收到HTTP请求时直接调用它,或者使用Gearman异步调用。请求量很大。
你不应该在请求内部处理这个,因为那样会导致服务器负担过重,无法控制请求量。所有大型网站都会使用消息队列来进行离线处理。
哪种选择更好呢?
在这种情况下,“更好”意味着速度和负载的最佳组合。生成图片的例子只是一个象征性的例子,这种方法也可以应用于数据库连接和其他事情。
你应该选择异步处理,因为除了能加快你的网站速度,最重要的原因是当负载很高时,你可以控制你的队列。你可以优先处理那些最重要的任务。
我认为分叉进程是比较耗费资源的。我会创建几个工作进程(可能在进程内部做一些线程处理)来应对负载。我可能会使用redis,因为它速度快,持续更新(antirez和pietern几乎每天都有提交),而且有一个非常好用且稳定的Python客户端库。可以使用blpop/rpush来模拟一个队列(任务)。