2010-11-28 26 views
0

J'ai le code python suivant qui attend des données provenant du port série, et l'écrit dans un fichier.Plusieurs écritures dans le fichier

import time 
import serial 

def write_log (text): 
    f = open('logger.log', 'a') 
    f.write(text) 
    f.close() 

ser = serial.Serial() 
ser.port = "/dev/ttyS0" 
ser.baudrate = 4800 
ser.open() 
if ser.isOpen(): 
    while 1: 
     while ser.inWaiting() <= 0: 
      time.sleep(1) 
      response = ser.read(ser.inWaiting()) 
      if len (response): 
       write_log(response) 
       print response 

Il fonctionne dans une certaine mesure, comme après un certain temps, il commence à se bloquer, ce qui porte le CPU tout le chemin, et ne pas écrire quoi que ce soit (ou d'écrire parfois que des morceaux de texte) au fichier .log.

Le processus ici est assez intensif, car mon port série écrira une chaîne de 8 octets chaque seconde, et ce script python est censé le recevoir et écrire son contenu dans le fichier journal.

Je pense que le problème ici est le fait que j'ouvre et ferme trop le fichier, ce qui rend l'ensemble du processus lent. Je ne suis pas un python wizz, donc toute aide ou conseil sur l'amélioration de ce code serait grandement apprécié.

Merci à l'avance,

+0

8 octets par seconde n'est pas très intense; 8 MiB/s peuvent être intensifs, mais la plupart des processeurs peuvent même faire face à cela. Même un Z80 fonctionnant à 4 MHz ne trouverait pas 8 octets par seconde intensifs. –

+0

Je me rends compte que ce n'est pas très intensif, mais en quelque sorte ce code cesse de répondre après un certain temps, et arrête de stocker quoi que ce soit. Je dis intensif, car il va continuer à essayer d'écrire des choses en série, même si le script python n'écrit rien dans le fichier texte –

+0

Le code semble lire à partir du périphérique série, ne pas écrire. –

Répondre

0

Je pense que le problème ici est que vous recherchez des mises à jour.

La fonction serial.read() de Python bloque en fait le thread courant jusqu'à ce que quelque chose devienne lisible sur le thread, jusqu'au timeout. Ce que vous devriez faire, par conséquent, est de sortir un autre thread pour gérer les E/S série. Avoir une boucle indéfiniment, vérifiant une condition (le thread principal veut que vous restiez à l'écoute et le port série est toujours disponible). Ce fil fera quelque chose comme:

while ser.isOpen() && thisthread_should_keep_doing_this: 
    response = ser.read(ser.inWaiting()) 
    if len(response): 
     write_log(response) 
     print response 

Ensuite, quand vous le voulez pour sortir, votre fil maître définit thisthread_should_keep_doing_this=False et quand votre thread esclave a terminé la lecture, il se tue.

Deux choses:

  • ont le délai d'attente de lecture relativement fréquemment.
  • Ne pas "tuer à distance" le fil. Passez-lui un message et faites-le se tuer. Tuer des fils à distance crée un désordre terrible.

Voir http://pyserial.sourceforge.net/examples.html#miniterm

+0

Je ne suis pas sûr de comprendre vraiment ce qu'il faut faire ici. Encore une fois, je ne suis pas un python wizz, et je n'ai jamais travaillé avec des threads. Votre idée semble cependant être une solution raisonnable à mon problème –

+0

@Marcos l'idée est assez simple, mais vraiment difficile à comprendre, si cela a du sens. Fondamentalement, bloquer IO est comme le sommeil. Votre thread va se réveiller à deux conditions: les données sortent, ou le délai expire. Ce que vous faites ensuite est de vérifier que le port est ouvert et que vous ne voulez pas quitter, puis essayez de relire et de laisser le bloc de lecture à distance. En créant deux threads, vous pouvez en sacrifier un à cette fin et un pour continuer avec l'activité principale du programme (même si cela n'attend que l'instruction "exit"). –

+0

En bloquant les E/S de cette façon, si vous recevez beaucoup de données, vous les lisez instantanément. Si ce n'est pas le cas, vous dormez pendant l'intervalle de temporisation. Avec VOTRE solution, vous dormez pendant 1 seconde et tirez tout ce qui est là. Donc pour cette seconde, vous pourriez utiliser des cycles d'horloge pour lire des données, mais vous ne le faites pas. Ensuite, il y a beaucoup de données ... et vous obtenez des résultats imprévisibles. –

1

Vous avez une boucle infinie dans votre code, et vous ne cassent pas de quand il y a un problème - ou le périphérique série n'est plus ouvert.

probablement utiliser:

while ser.isOpen(): 
    while ser.inWaiting() <= 0: 
     time.sleep(1) 
     response = ser.read(ser.inWaiting()) 
     if len(response): 
      write_log(response) 
      print response 

ou même:

while ser.isOpen() && ser.inWaiting() <= 0: 
    time.sleep(1) 
    response = ser.read(ser.inWaiting()) 
    if len(response): 
     write_log(response) 
     print response 

Je ne suis pas sûr du sommeil, que ce soit; vous feriez mieux d'attendre la lecture pour que les données deviennent disponibles. En y réfléchissant, ne sachant pas les méthodes disponibles dans la classe sérielle, plus je pense que la boucle principale devrait essayer de lire depuis le périphérique série, pendante heureusement s'il n'y a rien actuellement disponible, et ne s'arrêtant que lorsque la méthode d'entrée indique qu'il n'y a plus d'entrée à venir - l'appareil a été fermé sur vous, ou a échoué d'une manière ou d'une autre.

+0

Votre exemple disparaît après un certain temps –

+0

@Marcos: OK, mais sans spécification du paquet série (est-ce le standard Python? J'en doute) il va être difficile de savoir ce que vous devez faire. Doublement car je ne peux vraiment lire que Python et ne pas l'écrire couramment. Mais vous devriez viser à ce que la boucle (singulière - non imbriquée) soit lue de manière synchrone; il se bloque simplement dans la lecture jusqu'à ce qu'il y ait des données prêtes. Si cette fonction n'est pas déjà disponible, vous pouvez écrire une fonction pour la fournir. Si vous avez vraiment besoin d'interroger, vous pouvez vouloir interroger plus d'une fois par seconde, en utilisant une fonction de micro-sommeil. –