我正在尝试同步一种特殊的生产者/消费者问题。
这就是问题所在:
我有两个队列link_queue, page_queue
。
threadclass ProducePages_RequireLinks
(称为class A
),顾名思义,使用link_queue
中的项,并将每个链接中的任意数量(>=1)的页面放入page_queue
。
相反,主线程class ProduceLinks_RequirePages
(称为class B
)消耗page_queue
中的页面,并将任意数量(>=0)的链接排队到link_queue
。
现在class B
生成链接的速度可能比class A
生成页面的速度快。
另一方面,反过来也是可能的。
如何在Ruby1.9.2中正确地同步这些线程?
我试着同时使用监视器,但在某一点上,我最终陷入了僵局。
(如果我说的不准确,请通过评论告诉我,我会发布一些示例类)
编辑:
正在发生的事情的图片:
实例link_queue
初始化为1个项page_queue
初始化为0项
我们有4个class A
线程和1个class B
线程。每条线将是1个时间步。
线程A.1获取1个链接(linkq=0)输出1页(pageq=1)
线程B抓取1页(pageq=0)输出400个链接(linkq=400)
线程A.3获取1个链接(linkq=399)输出1页(pageq=1)
线程A.2获取1个链接(linkq=398)输出1页(pageq=2)
线程B抓取1页(pageq=1)输出100个链接(linkq=498)
线程A.1获取1个链接(linkq=497)输出1页(pageq=2)
线程A.4获取1个链接(linkq=496)输出1页(pageq=3)
线程B注意到linkq太大,等待linkq. …线程A.*继续工作。…之后(linkq=15)和(pageq=484)
现在我们有了相反的问题。
现在线程a必须等到pageq降到某个阈值以下。
否则我们会在某个时候耗尽内存。
干杯
最佳答案
无论您使用的是ruby还是其他语言,只要您有一个像您在这里描述的生产者-消费者设计,无论生产者和消费者是线程还是进程,您决不能假设消费者能够“跟上”生产者。必须始终使用有界队列。即使像您在评论中提到的那样使用外部队列也不能解决一般情况下的问题,因为虽然外部存储比ram大得多,但并不是无限的。
ruby标准库有SizedQueue
,您可以通过require 'thread'
获得它。SizedQueue
是一个线程安全队列,其大小受到限制。如果生产者线程在项目已满时尝试将其推送到队列中,则生产者将阻塞,直到消费者从队列中弹出项目(为新项目腾出空间)。这将给消费者一个“追赶”的机会。同样,如果使用者线程试图在项目为空时将其从队列中弹出,则使用者将阻塞,直到项目可用为止。
如果生产商限制了总吞吐量,它们将倾向于获得更多的cpu时间(因为消费者阻塞)。另一方面,如果消费者是瓶颈,他们将倾向于获得更多的CPU时间。这比允许生产者消耗系统资源来填满不断增长的条目数量要好,而消费者可以使用这些资源来处理积压工作。