Threading modulu

merhabalar arkadaşlar:
bir script yazdım bu script csv formatında olan dataları xlsx formatına çevirip başka bir xlsx(data dosyam) dosyası ile karşılaştırıp aynı olanları başka bir xlsx dosyasına yazıyor bunu döngüler halinde birden çok dosya vererek yapıyorum.

şimdi gelelim sorunuma threading modülunu kullanarak birinci fonksiyondan ilk dosyasını çıkartmasını bekleyip o dosya çıktıktan sonra ikinci bir fonksiyon devreye girerek yapması gerekenleri yapıcak.
yani özeetlersem iki döngüyü aynı zamanda çalıştırmak istiyorum ancak ikinci döngü birinci döngünün bir kez dönmesini beklemeli.

bunun için bir adet 0’a eşit olan bir değişken tanımlayıp birinci döngü içerisinde arttırdım ve threads2 olarak değişkene atadığım 2. döngüyü bir if blogunda bu değişken 1 veya 1den büyükse şeklinde ayarlayıp threads2.start() komutunu verdim ancak işe yaramıyor. Başka nasıl bi yolla çözebilirim bu durumu

belki fonksiyon1 içerisinde değişkeni tanımlayıp başka bir fonksiyon içerisine çekilirse sorun düzelebilir.
2 fonksiyon arasında sadece değişkeni nasıl çekebilirim?

Merhaba, kodlarınızı göremediğim için nasıl bir kod yapısına ihtiyacınız var bilemiyorum. Ama iki farklı thread’in çalışma koşullarını aşağıda paylaştığım örnekte olduğu gibi belirleyebilirsiniz. Aşağıdaki kodlarda mesela, func1 fonksiyonu bir listeye 10'a kadar eleman ekliyor. func1 fonksiyonunda, listeye eklenen her bir i döngü sonunda 1 birim arttırılıyor. i sayısı 10'a ulaşınca check isimli değişken True değerini alıyor ve i 1’e eşitleniyor. check değişkeni True olunca bu kez ikinci func2 fonksiyonu listeye eklenmiş olan elemanları silmeye başlıyor. Listede sadece 0 elemanı kalınca da check değişkeni False yapılıyor. Bu kez func1 fonksiyonu listeye tekrar eleman eklemeye başlıyor.
Kodlar:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import time
import threading


def func1(arg: list):
    global check
    check = False
    i = 0
    while True:
        if not check:
            if i == 10:
                check = True
                i = 1
            else:
                arg.append(i)
                print(arg)
                time.sleep(.1)
                i += 1
            
        
def func2(arg: list):
    global check
    while True:
        if check:
            if len(arg) > 1:
                arg.pop(-1)
                print(arg)
                time.sleep(.1)
            else:
                check = False
                

def main():
    liste = []
    t1 = threading.Thread(target=func1, args=(liste,))
    t2 = threading.Thread(target=func2, args=(liste,))
    t1.start()
    t2.start()
    
    
if __name__ == "__main__": 
    main()

Bu kodları çalıştırdığınızda almamız gereken çıktı ise şöyle:

[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4, 5]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6, 7]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
[0, 1, 2, 3, 4, 5, 6, 7]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5]
[0, 1, 2, 3, 4]
[0, 1, 2, 3]
[0, 1, 2]
[0, 1]
[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4, 5]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6, 7]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
[0, 1, 2, 3, 4, 5, 6, 7]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5]
[0, 1, 2, 3, 4]
[0, 1, 2, 3]
[0, 1, 2]
[0, 1]
[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4, 5]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6, 7]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
[0, 1, 2, 3, 4, 5, 6, 7]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5]
[0, 1, 2, 3, 4]
[0, 1, 2, 3]
[0, 1, 2]
[0, 1]
[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4, 5]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6, 7]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
[0, 1, 2, 3, 4, 5, 6, 7]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5]
[0, 1, 2, 3, 4]
[0, 1, 2, 3]
[0, 1, 2]
[0, 1]
[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4, 5]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6, 7]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
[0, 1, 2, 3, 4, 5, 6, 7]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5]
[0, 1, 2, 3, 4]
[0, 1, 2, 3]
[0, 1, 2]
[0, 1]
[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4, 5]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6, 7]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
[0, 1, 2, 3, 4, 5, 6, 7]
[0, 1, 2, 3, 4, 5, 6]
[0, 1, 2, 3, 4, 5]
[0, 1, 2, 3, 4]
[0, 1, 2, 3]
[0, 1, 2]
[0, 1]
[0]

Burada yapılan işlem, bir thread üreteç olarak çalışıyorken, diğer threadin tüketici olarak çalışmasıdır. ne zaman işlem sırası thread1’e geçer ne zaman thread2’ye geçer bunu koşul durumlarıyla belirlemek lazım. Yukarıdaki fonksiyonlarda koşullar arg değişkeninin uzunluğu ve i sayısının büyüklüğü ile ilişkilidir.

Bu arada kodlarınızı paylaşırsanız, belki daha çok yardım alabilirsiniz.

kaynak kodlara şu link uzerinden ulaşabilirsiniz. threading.py

vermiş oldunuz koda benzer bir yöntem denedim fonk bir içerisinde bir değişken tanımlayıp daha sonra o değişkenin değerini aynı fonksiyon içerisinde değiştirerek koşuıl durumu yarattım ancak thread1.start() ve thread2.start() olarak komut verince istediğim işlemi yapmadı. thread1.run() ve th2.run() komutlarını verdiğim zaman önce birinci fonksiyonu bitirdi ardından ikinci fonksiyona geçti. yani thread kullanmadan öncede bu şekilde yapıyordu zaten.

benim yapmak istediğim olay tam olarak şu:
birinci fonksiyon bir döngü yaptıktan sonra ikinci fonksiyonda devreye girerek birinci ve ikinci fonksiyon aynı anda işlem yapıcaklar.

Birinci fonksiyon bir döngü yaptıktan sonra demişsiniz. Hangi döngüden bahsediyorsunuz? for a in list döngüsünden mi? Şayet öyleyse, test = 1'i bu döngü altına almanız gerekir. Yoksa read fonksiyonu bittikten sonra process fonksiyonu çalışır. bu arada list değişkeninin ismini başka bir şey yapmanız tavsiye edilir.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import pandas as pd
import os
from os import listdir
import threading


""" Bu scriptin çalışabilmesi için "pandas", "openpyxl", "xlrd"
    kütüphanelerine ihtiyaç vardır. """


def read():
    global test
    list = [] # list yerine başka bir isim kullanın.
    test = 0
    os.chdir("/home/detagen/Desktop/result/output")
    print(os.getcwd())
    print("İşleme alınan dosyalar", "\n")
    for z in os.listdir('/home/detagen/Desktop/result/output'):
        if z.endswith('goingxlsx.csv'):
            print(z)
            list.append(z)
    print("\n", len(list), "dosya işleme alınıyor", "\n")

    print()
    # for i in listdir("/home/detagen/Desktop/result/output"):
    #       if i.endswith('goingxlsx.csv'):
    #             list.append(i)
    # print(len(list), "dosya işleme alınıyor", "\n")

    for a in list:
        print('{} okunuyor'.format(a), "\n")
        csv = pd.read_csv(a)
        dfcsv = pd.DataFrame(csv)
        writer = pd.ExcelWriter('{}.xlsx'.format(a))
        dfcsv.to_excel(writer, index=False)
        writer.save()
        test = 1


def process():
    global test
    while True:
        if test == 1:
            xlsxlist=[]
            for b in listdir("/home/detagen/Desktop/result/output"):
                if b.endswith('goingxlsx.csv.xlsx'):
                    print('{} hastalık ekleniyor'.format(b), "\n")
                    xlsxlist.append(b)
                    database = pd.read_excel("/home/detagen/Desktop/programlar/ensembl-data/disease/disease-dataframe.xlsx")
                    dfdata = pd.DataFrame(database)
                    vcf = pd.read_excel(b)
                    dfvcf = pd.DataFrame(vcf)
                    merge = pd.merge(dfdata, dfvcf, on=dfdata.columns[0],
                                   how='inner')
                    merge.to_excel('{}-disease.xlsx'.format(b))
                    test = 0
            break


thread1 = threading.Thread(target=read)
thread1.start()

thread2 = threading.Thread(target=process)
thread2.start()

Yukarıdaki kodların basitleştirilmiş hali:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import time
import threading


def read():
    global test
    global a
    a = [1, 2, 3, 4, 5]
    for i in a:
        print("read fonksiyonu:", i)
        test = 1
        time.sleep(1)


def process():
    global test
    global a
    while True:
        if test == 1:
            for i in a:
                print("process fonksiyonu:", i ** 2)
                test = 0
                time.sleep(1)
            break
                

thread1 = threading.Thread(target=read)
thread1.start()

thread2 = threading.Thread(target=process)
thread2.start()

Bu kodları çalıştırdığınızda alacağınız çıktı:

read fonksiyonu: 1
process fonksiyonu: 1
read fonksiyonu: 2
process fonksiyonu: 4
read fonksiyonu: 3
process fonksiyonu: 9
read fonksiyonu: 4
process fonksiyonu: 16
read fonksiyonu: 5
process fonksiyonu: 25

Gördüğünüz gibi read fonksiyonunda döngünün ilk adımı bittikten sonra, process fonksiyonundaki döngünün ilk adımı başlıyor ve döngünün ikinci adımında beklemeye başlıyor. read fonksiyonu döngünün ikinci adımını bitirdikten sonra da process fonksiyonundaki döngünün ikinci adımına geçiliyor.

Bu kodun “pandas”, “openpyxl”, “xlrd” kutuphaneleri, bilumum ~detagen klasorleri ve turlu XLS dosyalari istemeyen versiyonu var midir? http://sscce.org/

Neyse, bariz bir sorun var zaten. Ana thread test'in 1 olmasini beklemiyor. Sadece bir kere kontrol edip, buyuk ihtimalle ≠1 bulup, “block” diyip bitiyor.

Thread’ler arasinda iletisimi global veya baska bir mekanizmayla paylasilan degiskenler uzerinden yapmak race condition’lara yol acar bu arada. threading modulunun kendisinde senkronizasyon primitifleri var, onlari kullanmak lazim. Mesela burada thread2, thread1'in isi (ilk loop’u) bittiginde set ettigi bir Event'i wait edebilir.

1 Like

aib arkadaşımızın bahsettiği konuyla alakalı bir örnek yapalım.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import threading


def read(event):
    global a
    a = [1, 2, 3, 4, 5]  
    event.set()
    while event.is_set():       
        for i in a:
            print("read fonksiyonu:", i)
            event.clear()
            event.wait(1)


def process(event):
    global a
    while not event.is_set():
        for i in a:
            print("process fonksiyonu:", i ** 2)
            event.wait(1)
            event.set()
            
            
event = threading.Event()

thread1 = threading.Thread(target=read, args=(event, ))
thread1.start()

thread2 = threading.Thread(target=process, args=(event, ))
thread2.start()

Çıktı:

read fonksiyonu: 1
process fonksiyonu: 1
read fonksiyonu: 2
process fonksiyonu: 4
read fonksiyonu: 3
process fonksiyonu: 9
read fonksiyonu: 4
process fonksiyonu: 16
read fonksiyonu: 5
process fonksiyonu: 25

Race condition var: process, read'in a'yi set etmesini beklemiyor. Degisken paylasmakla ilgili bahsettigim tehlike tam olarak buydu :slight_smile:

Bunun disinda event'i tam olarak nasil kullandigini anlamadim. Hangi thread’in loop edecegini, hangisinin bitecegini belirliyor ama 5 kere set/clear ediliyor? wait timeout ederse for loop’u bir sonraki degiskenle devam ediyor? Dis while’lar sadece birer kere calisiyor gibi gozukuyor?

event'i de clear+wait ve wait+set yaptigin icin buralarda da race condition var; bu ikili satirlarin calismasi atomik degil.


Genel olarak event, A’dan B’ye tek bir olayin bir kez gecip gecmedigini belirtmek icin kullaniliyor. Bir adet set, bir adet de wait'den fazlasini kullaniyorsan cok buyuk ihtimalle yanlis senkronizasyon primitifini kullaniyorsun.

Burada senkronizasyon icin lock veya binary semaphore gibi bir mekanizma kullanmak istemissin sanirim. wait yerine de time.sleep kullansan daha iyi.

Bu arada kod bir producer/consumer ornegi ve bunu en rahat cozme yolu queue kullanmak. Queue ile bu kod ikiser satira iner:

for i in [1, 2, 3, 4, 5]: queue.put(i)
while True: print(queue.get())

2 Likes

Kodları biraz açıklamaya çalışayım:
read fonksiyonu çalışmaya başladığında event.set() 1 kez çağrılıyor ve event, True ediliyor. Böylece while event.is_set() koşulu sağlanmış oluyor ve bu koşul altındaki işlemlere geçiliyor.

Koşulun içinde bir for döngüsü var. OP’un yapmak istediği şeye göre bir döngü oluşturmak istedim aslında. Döngünün 1. aşaması tamamlandıktan sonra process fonksiyonundaki döngünün 1. aşamasına geçileceği için, read fonksiyonunda print çağrıldıktan sonra event.clear() fonksiyonu çağrılıyor ve event bu şekilde False ediliyor.

event False edildikten sonra event.wait(1) ile bu read fonksiyonu beklemeye geçiyor.

process fonksiyonunda while not event.is_set() şeklinde bir koşul tanımlandığı için, read fonksiyonu event.clear()'ı çağırıp False değerini döndürdükten sonra bu döngü çalışmaya başlıyor.

Döngünün altında yine bir for döngüsü var. print fonksiyonu çalıştıktan sonra zaten read fonksiyonunda False edilmiş olan event, event.wait(1) fonksiyonu ile 1 saniye bekletiliyor.

Daha sonra process fonksiyonunda event tekrar set ediliyor. Event set edildikten sonra process fonksiyonundaki while not event.is_set() koşulu geçersiz kılındığı için, bu sefer read fonksiyonu çalışmaya başlıyor.

Yani burada read fonksiyondaki döngünün 1. adımı tamamlandıktan sonra process’ fonksiyonundaki döngüye geçiliyor. process fonksiyonundaki döngünün 1. adımı tamamlandıktan sonra da read fonksiyonunun 2. adımına geçiliyor.

Dıştaki while döngüleri sadece 1 kez çalışıyor evet. wait fonksiyonundan sonra diğer fonksiyon çalışmaya başlıyor.

Bu arada nasıl bir tehlikeden bahsediyorsunuz, paylaştığım örnek üzerinden biraz daha ayrıntı verebilir misiniz?

Bu arada şundan da bahsetmeliyim, çıktı olarak her zaman paylaştığım gibi bir çıktı almıyorum. Mesela şöyle bir çıktı da almıştım:

read fonksiyonu: 1
process fonksiyonu: 1
read fonksiyonu: 2
process fonksiyonu: 4
read fonksiyonu: 3
process fonksiyonu: 9
read fonksiyonu: 4
process fonksiyonu: 16
process fonksiyonu: 25
read fonksiyonu: 5

Gördüğünüz gibi burada process fonksiyonu read fonksiyonunu beklemeden iki kere çalışmış. Ama aynı programı bir daha çalıştırdığım zaman bir önceki mesajımda paylaştığım çıktı gibi bir çıktı da alabiliyorum.

aslında semaphore ile de bir örnek yaptım ama, onu paylaşmadım.

evet bir bakıma producer/consumer örneği bu.

Kodunuzu çalıştırdım ve çıktı şu şekilde oldu.

read fonksiyonu: 1
process fonksiyonu: 1
read fonksiyonu: 2
process fonksiyonu: 4
process fonksiyonu: 9
process fonksiyonu: 16
process fonksiyonu: 25
read fonksiyonu: 3
read fonksiyonu: 4
read fonksiyonu: 5

Sanırım @aib hocamın demek istediği, sizin event’i set edip 1 saniye bekletmeniz yarış durumunun önüne geçmiyor. Siz event.clear() dediğiniz anda ikisi de 1 sn’lik beklemeye geçerse, sonrasında event’i kimin set edeceği belli olmuyor. Eleman sayısı arttıkça, çıktı düzensiz olmaya başlıyor. Örneğin 10 eleman için çıktı

read fonksiyonu: 1
process fonksiyonu: 1
read fonksiyonu: 2
process fonksiyonu: 4
process fonksiyonu: 9
process fonksiyonu: 16
process fonksiyonu: 25
process fonksiyonu: 36
read fonksiyonu: 3
process fonksiyonu: 49
process fonksiyonu: 64
process fonksiyonu: 81
process fonksiyonu: 100
read fonksiyonu: 4
read fonksiyonu: 5
read fonksiyonu: 6
read fonksiyonu: 7
read fonksiyonu: 8
read fonksiyonu: 9
read fonksiyonu: 10

Aslında böyle bir soru için thread kullanmaya gerek yok bence.

Şöyle basit bir çözüm kullanılabilir

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import threading,time
state = "add"
liste = [1,2,3,4,5,6,7,8,9,10]

def read():
    global state
    for i in liste:
        while(state=="wait"):
            time.sleep(0.1)
            continue
        print(i)
        state="wait"

def process():
    global state
    for i in liste:
        while(state=="add"):
            time.sleep(0.1)
            continue
        print(i**2)
        state="add"

thread1 = threading.Thread(target=read)
thread1.start()
thread2 = threading.Thread(target=process)
thread2.start()

Evet, burada thread kullanmadan da benzer bir işlem yapılabilir ancak OP’a bir fikir vermesi açısından bir thread örneği paylaşmak istemiştim. pek uygun bir örnek olmadı sanırım. :slight_smile:

read fonksiyonunda event sadece 1 kez set ediliyor. set etme işlemi process fonksiyonunda gerçekleşiyor. ancak sizin de dediğiniz gibi çıktılarda bir düzensizlik meydana gelebiliyor.

event'i daha iyi anlayabilmek için daha çok örnek yapmam gerekiyor sanırım.

1 Like

Şöyle yapınca hiç bir sıkıntı çıkmıyor. Acaba bu doğru kullanım mı? Bir de siz deneyin.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import threading


def read(event):
    global count
    event.set()
    count = 0
    while count < 10:
        while event.is_set():       
            print("read fonksiyonu")
            event.clear()
            event.wait(1)
            count += 1


def process(event):
    global count
    while count < 10:
        while not event.is_set():
            print("process fonksiyonu")
            event.wait(1)
            event.set()

            
            
event = threading.Event()

thread1 = threading.Thread(target=read, args=(event, ))
thread1.start()

thread2 = threading.Thread(target=process, args=(event, ))
thread2.start()
1 Like

Çıktı sırası düzeldi. Kısaca mantık, anahtarı elinde bulundurma durumu üzerine kuruluyor. Bu konuyla ilgili birkaç kaynak paylaşmak isterim. Kritik kısım problemi ve yarış durumu ile ilgili bilgi edinebilirsiniz.

http://leventbayindir.net/wp-content/uploads/2013/07/bim301-hafta6.pdf
http://leventbayindir.net/wp-content/uploads/2013/07/bim301-hafta7.pdf

1 Like

O zaman calismanin detayli aciklamasini ve olasi hata noktalarini atlasak olur mu? Bu sekilde ince eleme yapmaktansa daha onemli seyler anlatabilecegimi dusunuyorum.

Aslinda race condition’lari analiz etmenin bir yolu, kodun sagina soluna sleep cagrilari yerlestirmek. Race condition olmayan kod, satirlarin calisma zamanlamasindan bagimsiz olarak, her sekilde ayni sonuca ulasacaktir.

Mesela a ile ilgili problemi hemen gostereyim:

import threading
import time

def read(ev):
    global a
    time.sleep(1) # <---------- stratejik yerlestirilmis sleep
    a = [1, 2, 3, 4, 5]
    ev.set()
    while ev.is_set():
        for i in a:
            print("read fonksiyonu:", i)
            ev.clear()
            ev.wait(1)

def process(ev):
    global a
    while not ev.is_set():
        for i in a:
            print("process fonksiyonu:", i ** 2)
            ev.wait(1)
            ev.set()

ev = threading.Event()
threading.Thread(target=read,    args=(ev,)).start()
threading.Thread(target=process, args=(ev,)).start()
Exception in thread Thread-2:
Traceback (most recent call last):
  File "/usr/lib/python3.7/threading.py", line 917, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.7/threading.py", line 865, in run
    self._target(*self._args, **self._kwargs)
  File "a.py", line 18, in process
    for i in a:
NameError: name 'a' is not defined

Veya process'in (error vermeden) while loop’una hic girmedigi versiyonu:

[...]
def read(ev):
    global a
    a = [1, 2, 3, 4, 5]
    ev.set()
    time.sleep(.000001) # <-------- set'teki bir page fault bile olabilir!
    while ev.is_set():
[...]

Bu durum, orijinal (sleep’siz) kodu denerken basima geldi hatta.

Dogru, cunku event'i bir “sira kimde” degiskeni olarak kullaniyorlar.

Fakat dis while count < 10 loop’lari, tight olarak calisiyorlar; icerideki while'a girilmedigi surece son hizla donup bosa CPU tuketiyorlar.

Event'in bu kullanim icin dogru olmamasinin sebebi ise tek tarafli calismasi: .clear() var ama .wait_unset() yok. Olsaydi, kodlar su sekilde simetrik olarak calisirdi:

def write(ev): while count<10: ev.wait_unset();  count = falan;  ev.set()
def  read(ev): while count<10: ev.wait_set();     filan(count);  ev.unset()

Dedigim gibi; threading.Event, bir thread’in bir noktaya ulasip ulasmadigini anla(t)mak icin kullanilan bir mekanizma. Bir set() + bir wait()'ten fazlasini kullaniyorsaniz muhtemelen hata yapiyorsunuz. clear'i niye koymuslar bilmiyorum bile. Standart kutuphanede bir kullanimini goremedim.

@aib

Bu son paylaştığım kodlardaki read fonksiyonunun başına time.sleep(1)'i ekleyince process fonksiyonundaki count ifadesi yüzünden bir NameError hatası yükseltiliyor. Bu hatayı ortadan kaldırmak için count'u dışarı almak zorunda kaldım.

Katılıyorum, while event.is_set() koşulu sağlanmazsa - ki bazı durumlarda sağlanmayacak - while count < 10 boş yere dönüp durmuş olur.

Okuduğum kadarıyla event.clear() fonksiyonu unset gibi bir işleve sahip ve event'i False yapıyor. Dökümantasyonda diyordu ki, wait() fonksiyonu event set edilene kadar yani True değerini verene kadar bekler. Bu sebeple process fonksiyonunda wait fonksiyonu set fonksiyonundan önce çağrıldı. process fonksiyonunda event True edilince, process'teki koşul sağlanmamış oluyor ama read fonksiyonundaki koşul sağlanmış oluyor ve bu yüzden read çalışmaya başlıyor. aslında yanlış ifade ettim, zaten bu fonksiyonlar bir kere çalışmaya başladıktan sonra zaten devamlı çalışır halde kalıyorlar. sizin de dediğiniz gibi koşul sağlanmadığı sürece döngüde hiç bir işlem yapılmıyor ama döngünün kendisi çalışmaya devam ediyor.

CPU tüketen işlemler olarak bahsettiğiniz işlemlerden anladıklarımı izninizle sizinle paylaşayım. Bu arada race condition dediğiniz durumu önlemek için count'u dışarı aldım.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import threading


def read():
    global count, event
    event.set()
    while count < 10:
        while event.is_set():       
            print("read fonksiyonu")
            event.clear()
            event.wait(1)
            count += 1
        else:
            print("döngü boşuna çalıştı")


def process():
    global count, event
    while count < 10:
        while not event.is_set():
            print("process fonksiyonu")
            event.wait(1)
            event.set()
        else:
            print("döngü boşuna çalıştı")

            
count = 0
           
event = threading.Event()

threading.Thread(target=read, args=(event, )).start()
threading.Thread(target=process, args=(event, )).start()

Bu kodları çalıştırdığım zaman aldığım çıktı şöyle oldu:

read fonksiyonu
process fonksiyonu
döngü boşuna çalıştı
read fonksiyonu
döngü boşuna çalıştı
process fonksiyonu
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
read fonksiyonu
döngü boşuna çalıştı
process fonksiyonu
döngü boşuna çalıştı
read fonksiyonu
döngü boşuna çalıştı
process fonksiyonu
döngü boşuna çalıştı
read fonksiyonu
döngü boşuna çalıştı
process fonksiyonu
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
read fonksiyonu
döngü boşuna çalıştı
process fonksiyonu
döngü boşuna çalıştı
döngü boşuna çalıştı
read fonksiyonu
döngü boşuna çalıştı
process fonksiyonu
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
read fonksiyonu
process fonksiyonu
döngü boşuna çalıştı
döngü boşuna çalıştı
döngü boşuna çalıştı
read fonksiyonu
döngü boşuna çalıştı
process fonksiyonu
döngü boşuna çalıştı
read fonksiyonu
döngü boşuna çalıştı
process fonksiyonu
döngü boşuna çalıştı
döngü boşuna çalıştı

Burada o kadar çok boşa çalışan işlem var ki işlemlerin çoğunu aslında bu işlemler oluşturuyor, yanılıyor muyum acaba? evet işlem sırası read'den sonra process olarak devam ediyor ancak çıktılar ne kadar da düzensiz değil mi?

Aynen, race condition’lar da boyle olusuyor zaten, “paralel” kodun hic bir zaman nasil calisacagi belli degil.

Istedigimiz sekilde calismasi icin birbirlerine baglandiklari noktalar belirliyoruz, bunu yapan aletlere de bu yuzden senkronizasyon primitifleri deniyor.

Evet, event’in set/wait ve clear’i var ama wait_clear’i yok, o yuzden dongu bosuna calisiyor. Condition'da var gibi duruyor, onunla daha rahat olabilir.

Ama zaten dedigim diger problemler var.

1 Like