如何防止Python多处理中的值重叠?

时间:2017-08-17 00:18:34

标签: python synchronization multiprocessing

我正在尝试Python多处理,我想使用Lock来避免重叠变量'es_id'值。

根据理论和示例,当进程调用lock时,'es_id'不能重叠,因为另一个进程无法访问它,但结果显示es_id经常重叠。

id值如何不重叠?

我的部分代码是:

def saveDB(imgName, imgType, imgStar, imgPull, imgTag, lock): #lock=Lock() in main
    imgName=NameFormat(imgName) #name/subname > name:subname
    i=0
    while i < len(imgName):
        lock.acquire()  #since global es_id
        global es_id

        print "getIMG.pt:save information about %s"%(imgName[i])
        cmd="curl -XPUT http://localhost:9200/kimhk/imgName/"+str(es_id)+" -d '{" +\
                        '"image_name":"'+imgName[i]+'", '+\
                        '"image_type":"'+imgType[i]+'", '+\
                        '"image_star":"'+imgStar[i]+'", '+\
                        '"image_pull":"'+imgPull[i]+'", '+\
                        '"image_Tag":"'+",".join(imgTag[i])+'"'+\
                        "}'"
        try:
                subprocess.call(cmd,shell=True)
        except subprocess.CalledProcessError as e:
                print e.output
        i+=1
        es_id+=1
        lock.release()

...

#main
if __name__ == "__main__":
    lock = Lock()
    exPg, proc_num=option()

    procs=[]
    pages=[ [] for i in range(proc_num)]
    i=1

    #Use Multiprocessing to get HTML data quickly
    if proc_num >= exPg:  #if page is less than proc_num, don't need to distribute the page to the process.
            while i<=exPg:
                    page=i
                    proc=Process(target=getExplore, args=(page,lock,))
                    procs.append(proc)
                    proc.start()
                    i+=1
    else:
            while i<=exPg: #distribute the page to the process
                    page=i
                    index=(i-1)%proc_num    #if proc_num=4 ->  0 1 2 3
                    pages[index].append(page)
                    i+=1
            i=0
            while i<proc_num:
                    proc=Process(target=getExplore, args=(pages[i],lock,))#
                    procs.append(proc)
                    proc.start()
                    i+=1

    for proc in procs:
            proc.join()

执行结果屏幕:

image showing duplicate eids

结果是 subprocess.call(cmd,shell = True)的输出。我使用XPUT向ElasticSearch添加数据,es_id是数据的id。我希望这些id顺序增加而不重叠。 (因为如果它们重叠,它们将被之前的数据覆盖)

我知道XPOST不需要使用锁码,因为它会自动生成ID,但我需要在将来顺序访问所有数据(比如读取一行文件)。

如果你知道在使用XPOST后如何顺序访问所有数据,你能告诉我吗?

2 个答案:

答案 0 :(得分:0)

您只提供了部分代码,因此我只能看到潜在的问题。对es_id一次访问进行锁定保护没有任何帮助。您必须在程序中出现的任何位置对其进行锁定保护 all 。也许最好为此目的创建一个访问函数,例如:

def increment_es_id():
    global es_id
    lock.acquire()
    es_id += 1
    lock.release()

可以从任何线程安全地调用它。

在您的代码中,将获取/释放调用尽可能紧密地移动到一起是一种很好的做法。在这里,您只需保护一个变量,因此您可以将获取/释放对移到es_id += 1语句之前和之后..

更好的是在上下文管理器中使用锁(尽管在这种简单的情况下它不会有任何区别):

def increment_es_id2():
    global es_id
    with lock:
        es_id += 1

答案 1 :(得分:0)

看起来您正在尝试使用锁访问全局变量,但全局变量是进程之间的不同实例。您需要使用的是共享内存值。这是一个有效的例子。它已经在Python 2.7和3.6上进行了测试:

from __future__ import print_function
import multiprocessing as mp

def process(counter):
    # Increment the counter 3 times.
    # Hold the counter's lock for read/modify/write operations.
    # Keep holding it so the value doesn't change before printing,
    # and keep prints from multiple processes from trying to write
    # to a line at the same time.
    for _ in range(3):
        with counter.get_lock():
            counter.value += 1
            print(mp.current_process().name,counter.value)

def main():
    counter = mp.Value('i') # shared integer
    processes = [mp.Process(target=process,args=(counter,)) for i in range(3)]
    for p in processes:
        p.start()
    for p in processes:
        p.join()

if __name__ == '__main__':
    main()

输出:

Process-2 1
Process-2 2
Process-1 3
Process-3 4
Process-2 5
Process-1 6
Process-3 7
Process-1 8
Process-3 9