我只是编写了一段简单的代码来对Redis +
gevent进行性能测试,以查看异步如何帮助性能,而令我惊讶的是发现性能不好。这是我的代码。如果您摆脱了前两行猴子打补丁的代码,那么您将看到“正常执行”的时间。
在Ubuntu 12.04 LTS VM上,我看到了
没有猴子补丁-54秒有猴子补丁-61秒
我的代码/方法有问题吗?这里有性能问题吗?
#!/usr/bin/python
from gevent import monkey
monkey.patch_all()
import timeit
import redis
from redis.connection import UnixDomainSocketConnection
def UxDomainSocket():
pool = redis.ConnectionPool(connection_class=UnixDomainSocketConnection, path = '/var/redis/redis.sock')
r = redis.Redis(connection_pool = pool)
r.set("testsocket", 1)
for i in range(100):
r.incr('testsocket', 10)
r.get('testsocket')
r.delete('testsocket')
print timeit.Timer(stmt='UxDomainSocket()',
setup='from __main__ import UxDomainSocket').timeit(number=1000)
这是预期的。
您在虚拟机上运行此基准测试,在该虚拟机上,系统调用的成本高于物理硬件上的成本。激活gevent时,它倾向于生成更多的系统调用(以处理epoll设备),因此最终会降低性能。
您可以通过在脚本上使用strace轻松地检查这一点。
如果没有gevent,则内部循环会生成:
recvfrom(3, ":931\r\n", 4096, 0, NULL, NULL) = 6
sendto(3, "*3\r\n$6\r\nINCRBY\r\n$10\r\ntestsocket\r"..., 41, 0, NULL, 0) = 41
recvfrom(3, ":941\r\n", 4096, 0, NULL, NULL) = 6
sendto(3, "*3\r\n$6\r\nINCRBY\r\n$10\r\ntestsocket\r"..., 41, 0, NULL, 0) = 41
使用gevent,您将发生以下情况:
recvfrom(3, ":221\r\n", 4096, 0, NULL, NULL) = 6
sendto(3, "*3\r\n$6\r\nINCRBY\r\n$10\r\ntestsocket\r"..., 41, 0, NULL, 0) = 41
recvfrom(3, 0x7b0f04, 4096, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
epoll_ctl(5, EPOLL_CTL_ADD, 3, {EPOLLIN, {u32=3, u64=3}}) = 0
epoll_wait(5, {{EPOLLIN, {u32=3, u64=3}}}, 32, 4294967295) = 1
clock_gettime(CLOCK_MONOTONIC, {2469, 779710323}) = 0
epoll_ctl(5, EPOLL_CTL_DEL, 3, {EPOLLIN, {u32=3, u64=3}}) = 0
recvfrom(3, ":231\r\n", 4096, 0, NULL, NULL) = 6
sendto(3, "*3\r\n$6\r\nINCRBY\r\n$10\r\ntestsocket\r"..., 41, 0, NULL, 0) = 41
当recvfrom调用处于阻塞状态(EAGAIN)时,gevent返回事件循环,因此需要执行其他调用来等待文件描述符事件(epoll_wait)。
请注意,对于任何事件循环系统,这种基准测试都是最坏的情况,因为您只有一个文件描述符,因此无法在多个描述符上分解等待操作。此外,由于所有内容都是同步的,因此异步I
/ O在这里无法改善任何内容。
对于Redis来说,这也是最坏的情况,因为:
它会产生许多到服务器的往返
它会系统地连接/断开连接(1000次),因为该池是在UxDomainSocket函数中声明的。
实际上,您的基准测试并不测试gevent,redis或redis-py:它行使VM在2个进程之间维持乒乓游戏的能力。
如果要提高性能,则需要:
使用流水线减少往返次数
使池在整个基准中持久存在
例如,考虑使用以下脚本:
#!/usr/bin/python
from gevent import monkey
monkey.patch_all()
import timeit
import redis
from redis.connection import UnixDomainSocketConnection
pool = redis.ConnectionPool(connection_class=UnixDomainSocketConnection, path = '/tmp/redis.sock')
def UxDomainSocket():
r = redis.Redis(connection_pool = pool)
p = r.pipeline(transaction=False)
p.set("testsocket", 1)
for i in range(100):
p.incr('testsocket', 10)
p.get('testsocket')
p.delete('testsocket')
p.execute()
print timeit.Timer(stmt='UxDomainSocket()', setup='from __main__ import UxDomainSocket').timeit(number=1000)
使用此脚本,我获得了大约3倍的性能提升,并且gevent几乎没有开销。
问题内容: 如果html文件是本地文件(在我的C驱动器上),则可以使用,但是如果html文件在服务器上并且图像文件是本地文件,则无法使用。这是为什么? 任何可能的解决方法? 问题答案: 如果客户端可以请求本地文件系统文件,然后使用JavaScript找出其中的内容,则将是一个安全漏洞。 解决此问题的唯一方法是在浏览器中构建扩展。Firefox扩展和IE扩展可以访问本地资源。Chrome的限制更为严
问题内容: 为什么我们需要特定于数据库的功能,例如mysql_real_escape_string()?addlashes()不能做什么? 暂时忽略了参数化查询的高级替代方案,是一个仅使用addlashes()的web应用仍然容易受到SQL注入的攻击,如果是,怎么办? 问题答案: 当处理多字节编码的字符串时,加号通常不够好。
从表面上看,具有的优点,使其听起来像将超过。一旦完全成熟,还有什么理由使用吗? 注意:我不是在问vs(如data.table vs dplyr:一个能做得好而另一个做得不好吗?),但是考虑到对于特定的问题,一个比另一个更好,为什么不是使用的工具。
我想做一个跟https://geojson.io/一样的可交互的地球,而且还不卡,请问应该用什么方案实现?
我能用一个lambda表达式来完成这一切吗?
我正在做一个项目,我的意图是运行一个玉米作业,并发送邮件给我的朋友,祝他们生日,我能够从MySQL DB获取电子邮件,并将其与当前日期进行比较,但当涉及到发送电子邮件时,我得到NullPointerException。 我确信应用程序属性没有问题,我在其他项目中也使用了它们,它们的功能正常 这是我得到以下信息的错误