Liste erweitern mit variabler Anzahl

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
BlackJack

@mobby: `qsize()` ist nicht zuverlässig, das liefert die ungefähre Anzahl der Elemente in der Queue. Was auch in der Dokumentation stehen sollte. Du musst die auf der anderen Seite mit `get()` wieder heraus holen und *dort* zählen. Wenn Du `qsize()` die Anzahl feststellst und danach die Queue leerst kann nach dem ”zählen” und vor dem Leeren ja vom anderen Thread ein Element in die Queue gesteckt werden, welches dann nicht gezählt wurde und mit dem Leeren verloren geht. Das `get()` darf nicht blockierend sein, weil Du ja in regelmässigen Abständen den aktuellen Zählwert in die Datenbank schreiben möchtest.

Ob Du `task_done()` und `join()` brauchst oder überhaupt verwenden kannst, hängt davon ab wie das Programmende vorgesehen ist, und was dabei dann wichtig ist.

Ich würde hier aber wahrscheinlich nicht mit einer Queue arbeiten weil das alles etwas umständlich aussieht. Ein threadsicheres Zähler-Objekt mit einer `increase()`- und einer `get_and_reset()`-Methode erscheint mir irgendwie einfacher.

Code: Alles auswählen

from threading import Lock


class Counter(object):
    def __init__(self, value=0):
        self.value = value
        self.lock = Lock()

    def increase(self):
        with self.lock:
            self.value += 1

    def get_and_reset(self):
        with self.lock:
            result = self.value
            self.value = 0
        return result
Benutzeravatar
mobby
User
Beiträge: 76
Registriert: Donnerstag 17. April 2014, 09:43

@BlackJack: Besten Dank, habe ich das dann so richtig umgesetzt?

Code: Alles auswählen

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


import time
from contextlib import closing
from itertools import groupby
from threading import Thread
from threading import Lock
from time import sleep
import MySQLdb as db
import pifacedigitalio as piface


def insert_into_database(timestamp, date, time,  amount):
    with closing(
        db.connect(
		host='',
	 	user='', 
		passwd='', 
		db='')
    ) as connection:
        connection.cursor().execute(
            'INSERT INTO S0_Zaehler_01(Zeitstempel, Datum, Zeit, Impulsanzahl) VALUES (%s, %s, %s, %s)',
            (timestamp, date, time, amount)
        )
        connection.commit()


def blink_led():
    piface.digital_write(0,1)
    sleep(0.1)
    piface.digital_write(0,0)


class Counter(object):
    def __init__(self,value=0):
        self.value = value
        self.lock = Lock()

    def increase(self):
        with self.lock:
            self.value += 1

    def get_and_reset(self):
        with self.lock:
            result = self.value
            self.value = 0
        return result  


def write_leading_edge_count(count):
    intervall = 5
    timestamp = int(time.time() / intervall) * intervall
    while True:
	timestamp += intervall
        time.sleep(max(0, timestamp-time.time()))
        leading_edge_count = count.get_and_reset()
        datum = str(time.strftime("%d-%m-%Y"))
        uhrzeit = str(time.strftime("%H:%M:%S"))
        insert_into_database(timestamp, datum, uhrzeit, leading_edge_count)


def start_writer(count):
    thread = Thread(target=write_leading_edge_count, args=(count,))
    thread.setDaemon(True)
    thread.start()


def iter_values(frequency):
    while True:
        yield piface.digital_read(0)
        sleep(1.0 / frequency)


def iter_changes(frequency):
    for value, _ in groupby(iter_values(frequency)):
        yield value


def main():
    piface.init()
    count = Counter()
    start_writer(count)
    for value in iter_changes(100):
        if value == 1:
            count.increase()
            blink_led()

			
if __name__ == '__main__':
    main()
Funktioniert auf jeden Fall! Ich frage dann noch alle Fehler beim Verbinden zur MySQL ab und sende, falls ein Fehler auftritt, diesen über ein SMTP Modul an einen Emailempfänger. Code dazu folgt ;) Danke!
Benutzeravatar
mobby
User
Beiträge: 76
Registriert: Donnerstag 17. April 2014, 09:43

So, habe jetzt noch die erwähnten Funktionen eingebettet. Nur eine Frage ist noch offen, wenn ich das momentan auskommentierte sys.exit() versuche, schließt das ja nur diesen Thread. Wie kann ich an der Stelle das gesamte Skript stoppen? Danke!

Code: Alles auswählen

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


import sys
from contextlib import closing
from time import sleep
import MySQLdb as db
import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText


def send_email(content, mysql_error_code):
    fromaddr = ""
    toaddr = ""
    msg = MIMEMultipart()
    msg['From'] = fromaddr
    msg['To'] = toaddr
    msg['Subject'] = "MySQL Error: " + mysql_error_code
    msg.attach(MIMEText(content))
    text = msg.as_string()
    server = smtplib.SMTP('', )
    server.set_debuglevel(1)
    server.ehlo()
    server.starttls()
    server.login('','')
    server.sendmail(fromaddr, toaddr, text)
    server.quit()


def insert_into_database(timestamp, date, time,  amount):
    try:
        with closing(
            db.connect(
		    host='',
	 	    user='', 
		    passwd='', 
		    db='')
        ) as connection:
            connection.cursor().execute(
                'INSERT INTO S0_Zaehler_01(Zeitstempel, Datum, Zeit, Impulsanzahl) VALUES (%s, %s, %s, %s)',
                (timestamp, date, time, amount)
            )
            connection.commit()
    except db.Error, e:
        mysql_error_code = str(e.args[0])
        mysql_error_message = str(e.args[1])
        content = "Es kann keine Verbindung zum Server hergestellt werden. \n\n" + mysql_error_message
	send_email(content, mysql_error_code)
#        sys.exit()	
Vielen Dank für Feedback!
Antworten