Python:url轮询和发布的体系结构

Python:url轮询和发布的体系结构,python,architecture,concurrency,Python,Architecture,Concurrency,我有一个简单的问题。我必须获取一个url(大约每分钟一次),检查是否有任何新内容,如果有,将其发布到另一个url 我的工作系统每分钟都有一个cronjob,基本上: for link in models.Link.objects.filter(enabled=True).select_related(): # do it in two phases in case there is cross pollination # get posts twitter_posts,

我有一个简单的问题。我必须获取一个url(大约每分钟一次),检查是否有任何新内容,如果有,将其发布到另一个url

我的工作系统每分钟都有一个cronjob,基本上:

for link in models.Link.objects.filter(enabled=True).select_related():
    # do it in two phases in case there is cross pollination

    # get posts
    twitter_posts, meme_posts = [], []
    if link.direction == "t2m" or link.direction == "both":
        twitter_posts = utils.get_twitter_posts(link)

    if link.direction == "m2t" or link.direction == "both":
        meme_posts = utils.get_meme_posts(link)

    # process them
    if len(twitter_posts) > 0:
        post_count += views.twitter_link(link, twitter_posts)

    if len(meme_posts) > 0:
        post_count += views.meme_link(link, meme_posts)

    count += 1

msg = "%s links crawled and %s posts updated" % (count, post_count)
这对于我现在拥有的150个用户来说非常有效,但是它的同步性让我感到害怕。我有内置的url超时,但在某个时候,我的cronjob将花费>1分钟,而我将有一百万个url超时互相覆盖

那么,我应该如何重写它呢

一些问题:

  • 我不想太用力地攻击API,以防它们阻止我。因此,我希望在任何时候最多有5个到任何API的开放连接
  • 用户一直在系统中注册,因为这运行,所以我需要一些方法来添加他们
  • 我希望这是规模以及可能
  • 我希望尽可能多地重用现有代码
所以,我有一些想法:

  • 为每个
    链接生成一个线程
  • 使用-保持一个正在运行的进程,cronjob只是确保该进程正在运行
  • 使用-不太了解它
  • 询问StackOverflow:)

您将如何做到这一点?

最简单的方法是:使用一个长时间运行的进程(在它自己的线程上)来处理调度——通过将请求发布到;有一个固定大小的线程池(您可以找到一个预先制作的线程池,但很容易调整它或自己滚动),从队列中获取请求(并通过单独的队列返回结果)。如果需要,注册和其他系统功能可以由几个专用线程处理

线程并没有那么糟糕,只要(a)您不必担心它们之间的同步(只需让它们通过本质上线程安全的队列实例进行通信,永远不共享对任何非严格只读的结构或子系统的访问),以及(b)您永远不会有太多线程(使用一些专用线程来实现专门的功能,包括调度,并使用一个小线程池来完成一般工作--决不为每个请求生成一个线程,或者类似的事情,这将导致崩溃)


Twisted可以更具可扩展性(以较低的硬件成本),但如果您将您的体系结构(和队列)集中在一起,您就有了一种内置的方法来扩展系统(通过购买更多硬件),以使用非常类似的模块来代替…几乎是替代品的减少,并且可能会有数量级的扩展!-

好的,谢谢。这样做,它看起来仍然是IO连接中最大的拦截器(我95%的时间在套接字的
read()
,4%的时间在
connect()
)。某种类型的持久连接会有帮助吗?如果是这样的话,有什么实现建议吗?即使您只连接到一台主机,使用连接池所能获得的最佳加速率是4%——几乎不值得这么复杂(而且您还是需要连接到多台主机,对吗?)。只需在池中放入足够多的线程,以便有足够多的并发操作(而不是任意限制为5,根据经验确定,从低开始,但如果数字告诉您需要,则逐渐增加)。花费那么多时间等待来自多个源的I/O的任务是最适合线程化的任务(尽管Twisted更好,但也不多!)。遗憾的是,它只有两个不同的来源,所以我担心如果我添加太多的线程,我会被它们阻止。看起来我的性能已经接近极限了,
queue
是否比
collections好。为此,deque
?如果我的线程向数据库写入状态(获取一个新的oauth令牌等),那么是不是很糟糕?我是否应该将该操作排队(主要重构)?collections.deque不是线程安全的:queue.queue是其上的线程安全包装器。有些DB API是线程安全的(通常当每个线程都有一个单独的连接,或者在某些情况下甚至只有一个单独的游标时)——您需要检查要使用的特定连接。但是,将数据库放在一个有自己队列的专用线程后面绝不是一个主要的重构——尽管它足够大,足以引起一个单独的问题;-)。但如果你认为这是主要的,那么扭曲的或任何类似的想法都是正确的!-)。顺便说一句,Stackless对w/I-O绑定的任务帮助不大。