Wie kann ich den parallelen Prozess unabhängig von der Hauptsache mit dem Multiprocessing-lib oder anderen Weg laufen lassen? (Der Beispielcode ist jetzt mit Gabel)Wie kann ich eine Funktion parallel ausführen und nachdem das Hauptprogramm beendet wurde, läuft er weiter?
Lange Geschichte
Nun, ich war ein kleines Skript für Back-End meiner conky Konfigurationen zu schreiben und eine davon ist ein rss_parser.py
, das eine Reihe von Titeln erhalten/URLs und stdout anziehen. Kürzlich habe ich mich über etwas gefragt, um neue Benachrichtigungen unter Verwendung Notify
von GTK
zu aktivieren, wenn etwas Neues auf der RSS-Liste erscheint.
Aber ich habe ein Problem hier. Ich habe eine Aktion zum Öffnen des Links eingerichtet. Wenn meine Benachrichtigung aktiv ist, kann ich den Browser anklicken und öffnen. Dieser Teil des Codes muss warten, bis der Benutzer klickt oder die Benachrichtigungen schließen, für die eine ordnungsgemäße Ereignisschleife ausgeführt wird. Dies steht jedoch in Konflikt mit anderen Sache: , um meine Conky zu aktualisieren Ich brauche zu meinem Hauptskript zu beenden, ohne die Benachrichtigungen Teil zu erwarten! Also meine Idee ist die Benachrichtigungen parallel geschaltet.
Der Kodex from Hell
habe ich versucht, dies mit diesem vollständigen Code code: (überprüfe die parallel_notify
Funktion)
#!/usr/bin/env python
# coding=utf-8
#
# Python Script
#
# Copyleft © Manoel Vilela
#
#
import feedparser
from argparse import ArgumentParser
from string import ascii_letters as alphabet
from os import fork
import json
import sys
import webbrowser
import gi
gi.require_version('Notify', '0.7')
from gi.repository import GObject # noqa
from gi.repository import Notify # noqa
class RssNotifier(GObject.Object):
Notify.init("rss_conky")
notifications = []
def __init__(self, label):
self.label = label
self.loop = GObject.MainLoop()
super(RssNotifier, self).__init__()
GObject.timeout_add(100, self.exit_when_empty)
# lets initialise with the application name
def send_notification(self, title, text, url, file_path_to_icon=""):
n = Notify.Notification.new(title, text, file_path_to_icon)
# print('put notification')
self.notifications.append(n)
n.add_action(url, 'open', self.open_webbrowser)
n.connect('closed', self.close_notification, n)
n.show()
def send_rss(self, rss, url):
self.send_notification(self.label, rss, url, 'rss')
def open_webbrowser(self, n, url):
# print(':: webbrowse opening')
webbrowser.open(url)
def close_notification(self, n, arg):
self.notifications.remove(n)
# print(':: remove notification')
# print(':: notifications: ', self.notifications)
def exit_when_empty(self):
# print('exit check')
if not any(RssNotifier.notifications):
self.loop.quit()
return False
return True
CACHE_FILE = '.cache.json'
parser = ArgumentParser()
parser.add_argument(
'-u', '--url',
default="http://hackernews.demos.monkeylearn.com/feed.xml?",
dest='url',
type=str,
help='The url to be parsed'
)
parser.add_argument(
'-l', '--lines',
default=10,
dest='lines',
type=int
)
parser.add_argument(
'-w', '--width',
default=80,
dest='width',
type=int,
help='The horizontal limit'
)
parser.add_argument(
'-p', '--prefix',
default='- ',
dest='prefix',
type=str,
help='A prefix attached each feed'
)
parser.add_argument(
'-i', '--ignore',
default='',
dest='ignore',
type=str,
help='Useless string to remove'
)
parser.add_argument(
'-n', '--disable-notifications',
default=True,
dest='notifications',
action='store_false',
help='Disable notifications (default True)'
)
parser.add_argument(
'-r', '--rss-label',
default='RSS',
dest='rss_label',
type=str,
help='A simple label for what is fetching'
)
def get_label(entry):
if entry.get('tags'):
label = '{}: '.format(entry.get('tags').pop()['term'])
else:
label = ''
return label
def long_title_clean(title):
if len(title) > options.width:
return (title[:options.width] + '\n' +
' ' * (len(options.prefix)) +
long_title_clean(title[options.width:].strip()))
return title
def translate_name(url):
return '.' + ''.join([x for x in url if x in alphabet]) + '.cache'
def save_cache(new_cache, key):
cache_file = get_cache_file()
cache_file[key] = new_cache
with open(CACHE_FILE, 'w') as f:
json.dump(cache_file, f)
def get_cache(key):
return get_cache_file()[key]
def get_cache_text(key):
return '\n'.join((x for x, _ in get_cache(key)))
def get_cache_file():
try:
with open(CACHE_FILE, 'r') as f:
return json.load(f)
except:
return {}
def notify(new_rss):
notifier = RssNotifier(options.rss_label)
for rss, url in new_rss:
notifier.send_rss(rss, url)
notifier.loop.run()
def ignore_pattern(title):
return title.replace(options.ignore, '')
def parallel_notifications(new_rss):
if any(new_rss) and options.notifications:
if fork() == 0:
notify(new_rss)
def parse_print_rss(feed):
new_cache = []
for entry in feed['entries']:
if len(new_cache) >= options.lines:
break
label = get_label(entry)
output = '{}{}{!s}'.format(options.prefix, label, entry.title)
title = long_title_clean(ignore_pattern(output))
if title not in new_cache:
new_cache.append([title, entry['link']])
print(title)
return new_cache
if __name__ == '__main__':
loop = GObject.MainLoop()
options = parser.parse_args()
feed = feedparser.parse(options.url)
keyname = translate_name(options.url)
if not any(feed['entries']):
cache = get_cache_text(keyname)
print(cache)
sys.exit(0)
new_cache = parse_print_rss(feed)
old_cache = get_cache(keyname)
new_rss = [x for x in new_cache if x not in old_cache]
new_rss = new_cache # force use the new_cache
# the paralell part going here
parallel_notifications(new_rss)
save_cache(new_cache, keyname)
Der Code für faule Personen
import os
if os.fork() == 0:
os.setsid()
while True:
pass
print('shorter')
ps .: auf Conky, nie 'kürzer' wird gesendet, denn das passiert nie, er wartet auf das Kind! (Oder so ähnlich)
Erlittene Versuch
Beim ersten Versuch, benutzen ich multprocessing lib Setup einen neuen Prozess als Daemon (zum Hauptprogramm nicht erwarten Finish), aber dies nicht funktioniert. Übrigens, das schafft jetzt ein anderes Problem: wenn das Hauptprogramm fertig ist, das Process parallel Finish auch und jetzt habe ich nicht mehr Benachrichtigungen (oder einfach die Routine für den Klick funktioniert nicht, weil der Prozess bereits beendet ist) !! ! D:
EDIT-1
fork
Mit funktioniert gut, wenn ich versuche, im Terminal läuft! Aber ich habe ein echtes Problem in der Conky läuft! Warum das? In sublime
habe ich außerdem das gleiche Verhalten: der Elternprozess wird nur beendet, wenn das Kind verlässt.
Verwenden Sie diese Bibliothek: https://pypi.python.org/pypi/python-daemon/ –
Sie können mir ein Beispiel für diese Verwendung für mein Problem geben? Vielen Dank –