python多线程同步

python多线程同步,python,multithreading,synchronization,Python,Multithreading,Synchronization,我在使用cPython进行线程处理时遇到同步问题。我有两个文件,我解析它们并返回所需的结果。然而,下面的代码行为异常,返回三次而不是两次加号,并没有按照我将它们放入队列的顺序返回。代码如下: import Queue import threading from HtmlDoc import Document OUT_LIST = [] class Threader(threading.Thread): """ Start threading """ def _

我在使用cPython进行线程处理时遇到同步问题。我有两个文件,我解析它们并返回所需的结果。然而,下面的代码行为异常,返回三次而不是两次加号,并没有按照我将它们放入队列的顺序返回。代码如下:

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()
导入队列
导入线程
从HtmlDoc导入文档
OUT_LIST=[]
类线程器(threading.Thread):
"""
开始穿线
"""
定义初始(自我、队列、输出队列):
threading.Thread.\uuuuu init\uuuuuu(自)
self.queue=队列
self.out\u队列=out\u队列
def运行(自):
尽管如此:
如果self.queue.qsize()==0:break
路径,host=self.queue.get()
f=开放(路径“r”)
source=f.read()
f、 关闭()
self.out_queue.put((源、主机))
self.queue.task_done()
类处理器(threading.Thread):
"""
进程线程
"""
def u u初始(自,出队列):
self.out\u队列=out\u队列
self.l_first=[]
self.f\u append=self.l\u first.append
self.l_秒=[]
self.s\u append=self.l\u second.append
threading.Thread.\uuuuu init\uuuuuu(自)
def优先(自我,文档):
#一些代码来检索所需的文本,这是工作100%我手动测试它
def秒(自我,文档):
#一些代码来检索所需的文本,这是工作100%我手动测试它
def运行(自):
尽管如此:
如果self.out_queue.qsize()==0:break
doc,host=self.out\u queue.get()
如果主机==“第一个”:
自我优先(doc)
elif主机==“秒”:
第二自我(doc)
OUT_LIST.extend(self.l_first+self.l_second)
self.out\u queue.task\u done()
def main():
queue=queue.queue()
out\u queue=queue.queue()
queue.put((“…first.html”,“first”))
queue.put((“…second.html”,“second”))
qsize=queue.qsize()
对于范围内的i(qsize):
t=线程器(队列,输出队列)
t、 setDaemon(True)
t、 开始()
对于范围内的i(qsize):
dt=处理器(输出队列)
dt.setDaemon(True)
dt.start()
queue.join()
out_queue.join()
打印“
”。加入(输出列表) main()
现在,当我打印时,我想先打印“第一个”的内容,然后打印“第二个”的内容。有人能帮我吗


注意:我正在线程化,因为实际上我一次要连接10多个位置并检索结果。我相信线程是完成这样一项任务的最合适的方式,我不同意线程是最好的方式(我认为一些事件/选择机制会更好),但代码的问题可能在变量t和dt中。您在循环中有赋值,对象实例将存储在任何位置,所以您的线程/处理器的新实例可能在每个循环结束时被删除


如果您向我们展示这段代码的精确输出,会更加清晰。

我不同意线程是最好的方法(我认为一些事件/选择机制会更好),但您的代码的问题可能在变量t和dt中。您在循环中有赋值,对象实例将存储在任何位置,所以您的线程/处理器的新实例可能在每个循环结束时被删除

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

1)您无法控制作业完成的顺序。它取决于执行时间,所以要想返回所需的结果,您可以使用作业对象(如作业结果)创建全局字典:{'first':None,'second':None}并将结果存储在此处,这样您就可以按所需顺序获取数据

2)
self.first
self.second
应在每个已处理的单据之后清除,否则您将有重复的输入/输出列表

3) 您可以对子流程模块使用多重处理,例如,将所有结果数据放入CSV文件,并根据需要对其进行排序。

1)您无法控制作业完成的顺序。它取决于执行时间,所以要想返回所需的结果,您可以使用作业对象(如作业结果)创建全局字典:{'first':None,'second':None}并将结果存储在此处,这样您就可以按所需顺序获取数据

2)
self.first
self.second
应在每个已处理的单据之后清除,否则您将有重复的输入/输出列表

3) 例如,您可以使用子流程模块的多重处理,将所有结果数据放入CSV文件中,并根据需要对其进行排序

我之所以使用线程,是因为实际上我一次要连接10多个位置并检索结果。我相信线程是完成这项任务最合适的方式

线程实际上是管理多个并发连接最容易出错的方法之一。一种更强大、更可调试的方法是使用事件驱动的异步网络,如由实现的。如果您对使用此模型感兴趣,您可能希望签出

我之所以使用线程,是因为实际上我一次要连接10多个位置并检索结果。我相信线程是完成这项任务最合适的方式


线程实际上是管理多个并发连接最容易出错的方法之一。一种更强大、更可调试的方法是使用事件驱动的异步网络,如由实现的。如果您对使用此模型感兴趣,您可能需要查看。

我将多进程优先于多线程,因为同步问题太多,并且当您需要在多台服务器上运行脚本时,可能会有更高的并行级别。绑定I/O的线程很少受到GIL和上下文切换的影响。一根线消耗一根线