Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Bagaimana untuk menyelesaikan ralat penyegerakan berbilang benang Python?

Bagaimana untuk menyelesaikan ralat penyegerakan berbilang benang Python?

WBOY
WBOYasal
2023-06-24 18:26:461171semak imbas

Masalah penyegerakan berbilang benang Python adalah masalah biasa apabila menulis program serentak. Walaupun Python mempunyai modul threading terbina dalam, multi-threading Python bukanlah pelaksanaan yang selari kerana kewujudan Global Interpreter Lock (GIL). Tetapi dalam beberapa kes, masih perlu menggunakan multi-threading untuk meningkatkan kecekapan program Python. Artikel ini akan memperkenalkan beberapa kaedah untuk menyelesaikan masalah penyegerakan berbilang benang Python.

1. Gunakan mekanisme kunci

Kunci ialah mekanisme dalam Python untuk menyegerakkan akses berbilang benang kepada sumber yang dikongsi. Apabila berbilang utas melaksanakan operasi baca dan tulis pada sumber yang dikongsi, jika tiada langkah diambil, persaingan data dan hasil yang tidak konsisten akan berlaku Oleh itu, kunci diperlukan untuk memastikan hanya satu utas mengakses sumber yang dikongsi pada satu-satu masa.

Terdapat dua mekanisme kunci dalam Python: RLock dan Lock. Antaranya, Lock lebih cekap, tetapi masalah kebuntuan akan berlaku apabila kunci dimiliki berulang kali. RLock menyokong pemilikan kunci berulang, tetapi kecekapannya lebih rendah sedikit daripada Lock. Berikut ialah contoh penggunaan Kunci:

import threading

count = 0
lock = threading.Lock()

def hello():
    global count
    lock.acquire()
    for i in range(1000000):
        count += 1
    lock.release()

t1 = threading.Thread(target=hello)
t2 = threading.Thread(target=hello)
t1.start()
t2.start()
t1.join()
t2.join()
print(count)

Kunci digunakan di sini untuk melindungi operasi kemas kini kiraan pembolehubah yang dikongsi, mengelakkan masalah penyegerakan yang disebabkan oleh berbilang urutan mengakses kiraan pada masa yang sama.

2. Gunakan pembolehubah keadaan

Pembolehubah keadaan ialah mekanisme komunikasi antara utas Ia digunakan antara utas untuk menunggu keadaan tertentu berlaku dan kemudian memberitahu utas lain. Dalam pustaka threading terbina dalam Python, anda boleh menggunakan threading.Condition untuk mencipta pembolehubah keadaan.

Contoh berikut menggunakan pembolehubah keadaan untuk melaksanakan model pengeluar-pengguna:

import threading
import time

queue = []
MAX_NUM = 5
condition = threading.Condition()

class ProducerThread(threading.Thread):
    def run(self):
        nums = range(5)
        global queue
        while True:
            condition.acquire()
            if len(queue) == MAX_NUM:
                print("队列已满,生产者等待")
                condition.wait()
                print("生产者被唤醒")
            num = nums.pop()
            queue.append(num)
            print("生产者生产了", num)
            condition.notifyAll()
            condition.release()
            time.sleep(1)


class ConsumerThread(threading.Thread):
    def run(self):
        global queue
        while True:
            condition.acquire()
            if not queue:
                print("队列为空,消费者等待")
                condition.wait()
                print("消费者被唤醒")
            num = queue.pop(0)
            print("消费者消费了", num)
            condition.notifyAll()
            condition.release()
            time.sleep(2)

if __name__ == '__main__':
    t1 = ProducerThread()
    t2 = ConsumerThread()
    t1.start()
    t2.start()
    t1.join()
    t2.join()

Dalam contoh ini, pembolehubah keadaan digunakan untuk mengawal pelaksanaan pengeluar dan pengguna. Urutan pengeluar akan menunggu apabila baris gilir penuh, dan urutan pengguna akan menunggu apabila baris gilir kosong. Apabila data baharu dihasilkan atau digunakan, urutan menunggu lain akan dimaklumkan melalui kaedah notifyAll().

3. Gunakan baris gilir

Barisan ialah struktur data selamat benang yang boleh digunakan untuk mencapai penyegerakan dan komunikasi antara rangkaian. Dalam Python, modul baris gilir menyediakan dua kelas baris gilir yang menyokong berbilang benang: Baris gilir dan LifoQueue yang pertama ialah baris gilir masuk pertama, keluar dahulu, dan baris gilir keluar pertama yang terakhir. Menggunakan Queue boleh mengelakkan masalah menulis kunci dan pembolehubah keadaan sendiri.

Contoh berikut menggunakan Queue untuk melaksanakan model pengeluar-pengguna:

import threading
import time
import queue

q = queue.Queue()

class ProducerThread(threading.Thread):
    def run(self):
        nums = range(5)
        global q
        for num in nums:
            q.put(num)
            print("生产者生产了", num)
            time.sleep(1)


class ConsumerThread(threading.Thread):
    def run(self):
        global q
        while True:
            num = q.get()
            q.task_done()
            print("消费者消费了", num)
            time.sleep(2)

if __name__ == '__main__':
    t1 = ProducerThread()
    t2 = ConsumerThread()
    t1.start()
    t2.start()
    t1.join()
    t2.join()

Dalam contoh ini, Queue digunakan sebagai penampan antara pengeluar dan pengguna Benang pengeluar menghasilkan data dan memasukkannya ke dalam Dalam Baris, pengguna thread mengeluarkan data daripada Queue untuk kegunaan. Kaedah put() Queue dan kaedah get() adalah selamat untuk benang dan tidak perlu menggunakan kunci atau pembolehubah keadaan untuk penyegerakan.

Ringkasnya, walaupun pengaturcaraan berbilang benang Python bukanlah pelaksanaan yang benar-benar selari, ia boleh meningkatkan kecekapan program untuk beberapa tugas intensif IO. Walau bagaimanapun, apabila menulis program berbilang benang, perhatian khusus perlu diberikan kepada isu penyegerakan dan komunikasi antara utas untuk mengelakkan masalah seperti keadaan perlumbaan dan kebuntuan. Masalah penyegerakan berbilang benang boleh diselesaikan melalui mekanisme seperti kunci, pembolehubah keadaan dan baris gilir.

Atas ialah kandungan terperinci Bagaimana untuk menyelesaikan ralat penyegerakan berbilang benang Python?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn