Saya mencoba multiprocessing Python, dan saya ingin menggunakan Lock untuk menghindari nilai variabel 'es_id' yang tumpang tindih.

Menurut teori dan contoh, ketika suatu proses memanggil kunci, 'es_id' tidak dapat tumpang tindih karena proses lain tidak dapat mengaksesnya, tetapi, hasilnya menunjukkan bahwa es_id sering tumpang tindih.

Bagaimana nilai id tidak tumpang tindih?

Bagian dari kode saya adalah:

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()

Layar hasil eksekusi:

image showing duplicate eids

Hasilnya adalah output dari subprocess.call (cmd, shell = True). Saya menggunakan XPUT untuk menambahkan data ke ElasticSearch, dan es_id adalah id dari data tersebut. Saya ingin id ini meningkat secara berurutan tanpa tumpang tindih. (Karena mereka akan ditimpa oleh data sebelumnya jika mereka tumpang tindih)

Saya tahu XPOST tidak perlu menggunakan kode kunci karena secara otomatis menghasilkan ID, tetapi saya perlu mengakses semua data secara berurutan di masa mendatang (seperti membaca satu baris file).

Jika Anda tahu cara mengakses semua data secara berurutan setelah menggunakan XPOST, dapatkah Anda memberi tahu saya?

0
haeny 17 Agustus 2017, 03:18

2 jawaban

Jawaban Terbaik

Sepertinya Anda mencoba mengakses variabel global dengan kunci, tetapi variabel global adalah contoh yang berbeda antar proses. Yang perlu Anda gunakan adalah nilai memori bersama. Berikut adalah contoh kerja. Ini telah diuji pada Python 2.7 dan 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()

Keluaran:

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
0
Mark Tolonen 17 Agustus 2017, 03:46

Anda hanya memberikan sebagian dari kode Anda, jadi saya hanya dapat melihat potensial masalah. Tidak ada gunanya mengunci-melindungi satu akses ke es_id. Anda harus mengunci-melindungi mereka semua, di mana pun mereka muncul dalam program. Mungkin yang terbaik adalah membuat fungsi akses untuk tujuan ini, seperti:

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

Ini dapat dipanggil dengan aman dari utas apa pun.

Dalam kode Anda, merupakan praktik yang baik untuk memindahkan panggilan dapatkan/lepaskan sedekat mungkin dengan Anda. Di sini Anda hanya perlu melindungi satu variabel, sehingga Anda dapat memindahkan pasangan perolehan/pelepasan tepat sebelum dan sesudah pernyataan es_id += 1..

Lebih baik lagi adalah menggunakan kunci di manajer konteks (walaupun dalam kasus sederhana ini tidak akan ada bedanya):

def increment_es_id2():
    global es_id
    with lock:
        es_id += 1
0
Paul Cornelius 17 Agustus 2017, 00:45