2011-09-02 101 views
0

我在使用cPython进行线程时遇到同步问题。我有两个文件,我解析它们并返回所需的结果。但是,下面的代码奇怪地起作用,并且返回三次而不是两次,并且按照我将它们放入队列的顺序不返回。下面的代码:python多线程同步

import Queue 
import threading 
from HtmlDoc import Document 

OUT_LIST = [] 

class Threader(threading.Thread): 
    """ 
    Start threading 
    """ 
    def __init__(self, queue, out_queue): 
     threading.Thread.__init__(self) 
     self.queue = queue 
     self.out_queue = out_queue 


    def run(self): 
     while True: 
      if self.queue.qsize() == 0: break 

      path, host = self.queue.get() 

      f = open(path, "r") 
      source = f.read() 
      f.close() 

      self.out_queue.put((source, host))   
      self.queue.task_done() 



class Processor(threading.Thread): 
    """ 
    Process threading 
    """ 
    def __init__(self, out_queue): 
     self.out_queue = out_queue 
     self.l_first = [] 
     self.f_append = self.l_first.append 
     self.l_second = [] 
     self.s_append = self.l_second.append 
     threading.Thread.__init__(self) 


    def first(self, doc): 
     # some code to to retrieve the text desired, this works 100% I tested it manually 

    def second(self, doc): 
     # some code to to retrieve the text desired, this works 100% I tested it manually 

    def run(self): 
     while True: 
      if self.out_queue.qsize() == 0: break 

      doc, host = self.out_queue.get() 

      if host == "first": 
       self.first(doc) 
      elif host == "second": 
       self.second(doc) 

      OUT_LIST.extend(self.l_first + self.l_second) 

      self.out_queue.task_done() 


def main(): 

    queue = Queue.Queue() 
    out_queue = Queue.Queue() 

    queue.put(("...first.html", "first")) 
    queue.put(("...second.html", "second")) 

    qsize = queue.qsize() 

    for i in range(qsize): 
     t = Threader(queue, out_queue) 
     t.setDaemon(True) 
     t.start() 

    for i in range(qsize): 
     dt = Processor(out_queue) 
     dt.setDaemon(True) 
     dt.start() 

    queue.join() 
    out_queue.join() 

    print '<br />'.join(OUT_LIST) 

main() 

现在,当我打印,我想打印的“第一”首先,然后的“第二”内容的内容。谁能帮我?

注:我是线程,因为实际上我将不得不一次连接超过10个地方并检索其结果。我相信线程是完成这样的任务的最合适的方式

回答

2

我是线程,因为实际上我将不得不一次连接超过10个地方并检索其结果。我相信线程化是完成这样一个任务的最合适的方式。

线程实际上是管理多个并发连接的最容易出错的方法之一。更强大,更可调试的方法是使用事件驱动的异步网络,例如由Twisted执行。如果您有兴趣使用此型号,则可能需要查看this introduction

1

我不同意线程是最好的方式来做到这一点(IMO的一些事件/选择机制会更好),但你的代码的问题可能会在变量t和dt中。你在循环中有分配,并且对象实例存储在任何地方 - 所以有可能在每个循环结束时你的新线程/处理器实例被删除。

如果您向我们显示此代码的精确输出,将会更清楚。

0

1)您无法控制作业完成顺序。它取决于执行时间,所以要想返回结果,您可以使用作业对象创建全局字典,例如job_results:{'first':None,'second':None}并在此存储结果,而不是您可以根据需要获取数据为了

2)self.firstself.second应该在每次处理文档之后被清除,否则你就会有重复的OUT_LIST

3)您可以使用多处理与子模块,并把所有的结果数据到CSV文件,例如并按照你的意愿对它们进行排序。

+0

由于过度使用同步问题以及在需要在多台服务器上运行脚本时可能具有较高的平行度级别,因此我优先考虑多线程的多进程。 – varela

+0

I/O绑定的线程很少受GIL和上下文切换影响。线程比进程消耗更少的资源,在这种情况下,这看起来很好。 – Martin