Hallo Forum,
im Zuge einer Projektvereinigung ist die Frage aufgekommen ob es
möglich ist, über eine liste zu iterieren die während der iteration verändert
werden kann. (gem. Brainstorming)
Kann so etwas in python ohne viel Aufwand realisiert werden?
Nachtrag: Wenn das Ende der Liste erreicht wurde, soll mit dem ersten
item fortgefahren werden.
VG., chris
Never ending Iteration ;-)
- mkesper
- User
- Beiträge: 919
- Registriert: Montag 20. November 2006, 15:48
- Wohnort: formerly known as mkallas
- Kontaktdaten:
Öhm, mache eine Kopie und iteriere da drüber. Bist du durch, das Spiel von vorne. Über sich verändernde Listen iteriert Python nicht, sondern gibt dann eine Exception aus (und das ist gut so...).
hallo mkesper,
hatte ich auch schon gedacht. aber das produziert bestimmt ordentlich overhead und den kann ich leider nicht gebrauchen.
so weit ich weiß wurde, das auch schon mal in python gefixt. habs mal irgendwo auf nen maillist gelesen.
die liste verändert werden kann.
vg, chris
hatte ich auch schon gedacht. aber das produziert bestimmt ordentlich overhead und den kann ich leider nicht gebrauchen.
so weit ich weiß wurde, das auch schon mal in python gefixt. habs mal irgendwo auf nen maillist gelesen.
wozu? es muss do auch möglich sein auch dann zu iterieren wennund das ist gut so...
die liste verändert werden kann.
vg, chris
be or not to be
Weil bei einer sich veränderden Liste die Elemente über die iteriert wird nicht mehr eindeutig sind: Was ist das *nächste* Element, wenn man Elemente eingefügt / herausgenommen hat? Das, das am Anfang dem gerade aktuellen folgte? Oder dasjenige, das *jetzt* dem gerade aktuellen folgen wird? Wie soll der Interpreter das entscheiden?maxwell hat geschrieben:wozu? es muss do auch möglich sein auch dann zu iterieren wenn
die liste verändert werden kann.
Nein, besser ist es an der Stelle Ausnahmen zu werfen und so einen Haufen potentieller Bugs zu vermeiden.
Ggf. sind aber Listcomprehensions genau was Du suchst:
Code: Alles auswählen
l = [foo(item) for item in l]
HTH
Christian
hallo,
folgendes soll erreicht werden.
Es soll über eine Liste mit IO-Buffer Elementen iteriert werden.
Jeder Buffer gleicht von seinem Verhalten einer Liste + Condition
im "wait" Fall. Es soll aus jedem Buffer genau ein Element entnommen
und in eine Queue geschrieben werden an deren Ende Prozesse auf den Inhalt warten. Wenn kein Element im Buffer vorhanden ist, soll es beim
nächsten Buffer versucht werden.
Synchron gesehen, könnte man ja auch nur alles hintereinander in die
queue schreiben. Aber ich möchte es gerne asynchron hinbiegen, sodass jobs auch voneinander abhängig sein können. a la:
Prozess 1 -> Einlesen [100 Elemente]
Prozess 2 -> Auswerten [100 Elemente]
Im Prinzip geht es um eine gerechte Aufteilung der Jobs auf die
Prozesse. Bsp. Prozess 1 hat 40 Elemente bearbeitet und eigentlich könnten diese bereits von Prozess 2 abgearbeitet werden, sodass
Resultate existieren. Im synchronen Fall werden alle Elemente von
Prozess 1 bearbeitet bevor Prozess 2 die ersten Elemente erreicht.
vg. chris
Nachtrag:
Ich habe das wie folgt gelöst:
Alle jobs inkl. parameter werden als tuple in eine deque gestellt.
Der Verteiler Thread ließt aus der liste am hinteren ende via pop
und entnimmt ein Element. Anschließend stellt er das tuple wieder
vorne via appendleft() an.
folgendes soll erreicht werden.
Es soll über eine Liste mit IO-Buffer Elementen iteriert werden.
Jeder Buffer gleicht von seinem Verhalten einer Liste + Condition
im "wait" Fall. Es soll aus jedem Buffer genau ein Element entnommen
und in eine Queue geschrieben werden an deren Ende Prozesse auf den Inhalt warten. Wenn kein Element im Buffer vorhanden ist, soll es beim
nächsten Buffer versucht werden.
Synchron gesehen, könnte man ja auch nur alles hintereinander in die
queue schreiben. Aber ich möchte es gerne asynchron hinbiegen, sodass jobs auch voneinander abhängig sein können. a la:
Prozess 1 -> Einlesen [100 Elemente]
Prozess 2 -> Auswerten [100 Elemente]
Im Prinzip geht es um eine gerechte Aufteilung der Jobs auf die
Prozesse. Bsp. Prozess 1 hat 40 Elemente bearbeitet und eigentlich könnten diese bereits von Prozess 2 abgearbeitet werden, sodass
Resultate existieren. Im synchronen Fall werden alle Elemente von
Prozess 1 bearbeitet bevor Prozess 2 die ersten Elemente erreicht.
vg. chris
Nachtrag:
Ich habe das wie folgt gelöst:
Alle jobs inkl. parameter werden als tuple in eine deque gestellt.
Der Verteiler Thread ließt aus der liste am hinteren ende via pop
und entnimmt ein Element. Anschließend stellt er das tuple wieder
vorne via appendleft() an.
Zuletzt geändert von maxwell am Montag 23. November 2009, 12:55, insgesamt 1-mal geändert.
be or not to be
Und an welcher Stelle müsstest du da jetzt über eine Liste iterieren und diese gleichzeitig verändern?! Über eine Queue iteriert man ja nicht, sondern holt sich ein Element nach dem nächsten, bis die Q leer ist.
Edit: Du kannst die Buffer ja genauso als Queue implementieren.
Edit2: Das mit dem vorne anstellen ist sehr seltsam, warum nimmst du nicht einfach 2 Queues für jeden Prozess einen?!
btw: Man kann den Interpreter überlisten, dies ist jedoch AUF KEINEN FALL zu empfehlen.
Edit: Du kannst die Buffer ja genauso als Queue implementieren.
Edit2: Das mit dem vorne anstellen ist sehr seltsam, warum nimmst du nicht einfach 2 Queues für jeden Prozess einen?!
btw: Man kann den Interpreter überlisten, dies ist jedoch AUF KEINEN FALL zu empfehlen.
Code: Alles auswählen
>>> l = [1,2,3]
>>> inserted = False
>>> for val in iter(l):
... if val == 1 and not inserted:
... l.insert(0, 0)
... inserted = True
...
>>> l
[0, 1, 2, 3]
>>> for pos, value in enumerate(iter(l)):
... if value == 1:
... l.insert(pos, 0)
...
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
MemoryError
In genau dem Moment wenn der mainthread neue Buffer in dieUnd an welcher Stelle müsstest du da jetzt über eine Liste iterieren und diese gleichzeitig verändern
Liste einträgt.
Ich habe da wie folgt gelöst:
Code: Alles auswählen
a=(ta, iter([i for i in range(8)]), 3)
b=(tb, iter([i for i in range(5)]), 1)
c=(tc, iter([i for i in range(2)]), 2)
x=deque()
x.append(a)
x.append(b)
x.append(c)
while 1:
try:
z=x.pop()
a=_islice(z[1],z[2])
a=tuple(a)
print (z[0],a)
if not a:
continue
x.appendleft(z)
except Exception, e:
break
be or not to be
Dein Code ist sehr seltsam und nichtssagend (u.a. schlechte Variablennamen, was macht ``_isslice``). Kann gerade keine Parallelen zu deiner Beschreibung und deinem Code ziehen. Kannst du das mal genauer mit Code erläutern.
Außerdem kann man auch einen Generator-Ausdruck verwenden, statt ``iter(ListCompr)``, wobei xrange natürlich selbst schon einen Iterator zurückgibt:
Edit: Obwohl ich deinen Code nicht wirklich verstanden habe, habe ich das Gefühl, dass dein Problem mit 2 Queues gelöst wäre.
Edit2: Wo ist eigentlich die Iteration in deinem Codebeispiel? Diese Frage ist immer noch nicht beantwortet.
Edit3: Mir ist nochwas eingefallen. Du redest hier im Kontext von Threads und Prozessen, als wären sie das selbe. Ich hoffe dir ist bewusst, dass das nicht so ist. In diesem Zusammenhang sollte noch was gesagt werden: Eine Multithreading-Anwendung mit Python bringt *keine* Performance-Vorteile. Im Gegenteil hat man durch den GIL sogar noch Overhead. Um mit Python und einem Multicore Performance-Vorteile zu erziehlen, gibt es das Modul ``multiprocessing``. In dem Modul gibt es z.B. auch schon die Klasse ``Queue``. Schau dir mal die Beispiele in der Doku an, du wirst sehen, dass dieses Modul normal alle Funktionalitäten bereitstellt, die du benötigst, ohne auf solche seltsamen Konstrukte wie beschrieben und gezeigt zurückgreifen zu müssen.
Außerdem kann man auch einen Generator-Ausdruck verwenden, statt ``iter(ListCompr)``, wobei xrange natürlich selbst schon einen Iterator zurückgibt:
Code: Alles auswählen
iter([i for i in xrange(3)])
# äquivalent
(i for i in xrange(3))
# äqu.
xrange(3)
Edit2: Wo ist eigentlich die Iteration in deinem Codebeispiel? Diese Frage ist immer noch nicht beantwortet.
Edit3: Mir ist nochwas eingefallen. Du redest hier im Kontext von Threads und Prozessen, als wären sie das selbe. Ich hoffe dir ist bewusst, dass das nicht so ist. In diesem Zusammenhang sollte noch was gesagt werden: Eine Multithreading-Anwendung mit Python bringt *keine* Performance-Vorteile. Im Gegenteil hat man durch den GIL sogar noch Overhead. Um mit Python und einem Multicore Performance-Vorteile zu erziehlen, gibt es das Modul ``multiprocessing``. In dem Modul gibt es z.B. auch schon die Klasse ``Queue``. Schau dir mal die Beispiele in der Doku an, du wirst sehen, dass dieses Modul normal alle Funktionalitäten bereitstellt, die du benötigst, ohne auf solche seltsamen Konstrukte wie beschrieben und gezeigt zurückgreifen zu müssen.
Zuletzt geändert von ms4py am Montag 23. November 2009, 13:38, insgesamt 1-mal geändert.
@ ice2k3
der code ist nur beispiel und wird niemals produktiv. zumindest in der form.
ja du hast recht man kann auch xrange nehmen. aber hier unbrauchbar -> siehe islice. Es soll außerdem auch nur eine liste simuliert werden.
Sieht mans nun besser?
der code ist nur beispiel und wird niemals produktiv. zumindest in der form.
Code: Alles auswählen
from itertools import isslice as _islice
Code: Alles auswählen
def target1(): pass
def target2(): pass
def target3(): pass
pendings = deque()
# tuple structure:
# [target_function], [list_iterator], [chunksize]
# target function -> aufgerufene funktion durch den prozess
# list_iterator -> erzeugter iterator über die argumenten liste
# chunksize -> length der an das target zu übergebene argumentenliste
pendings.append((target1, iter([i for i in range(10)]), 2))
pendings.append((target2, iter([i for i in range(10)]), 1))
pendings.append((target3, iter([i for i in range(10)]), 3))
def distribute(pendings):
while 1:
try:
# lade job aus queue
sample = pendings.pop()
# schneide aus der liste anzahl der argumente
args = islice(sample[1], sample[2])
# verpacke es als tuple
args = tuple(args)
# wenn tuple leer dann gehe zum nächsten job
if not args:
continue
# halte hier und gebe das tuple und das target zurück
yield (sample[0], args, sample[2])
# anschließend stelle den job hinten an
pendings.appendleft(sample)
except Exception, e:
# ok ende erreicht!!!
break
for i in distribute(pendings):
print i
# hier dann rein in die pipe queue
Wie ???Obwohl ich deinen Code nicht wirklich verstanden habe, habe ich das Gefühl, dass dein Problem mit 2 Queues gelöst wäre.
be or not to be
Siehe mein Edit3 von oben!
Außerdem ist mir nicht klar, warum du das Ausschneiden erst innerhalb der Schleife machst und nicht schon beim Hinzufügen.
(Mir ist immer noch nicht klar, wo die Iteration sein soll, die gleichzeitig über eine Liste iteriert und diese verändert, allerdings ist das mit einer Lösung mit ``multiprocessing`` auch nicht wichtig...)
Edit: Außerdem sollte deine try..except wirklich nur die Exception abfangen, dass die Queue leer ist. Man sollte nie allgemein ``Exception`` abfangen, und vor allem nicht über so einen langen Codeblock. Es gibt ja auch noch try..except..else
Edit2: ``class multiprocessing.JoinableQueue`` wär vielleicht auch sinnvoll einzusetzen.
Außerdem ist mir nicht klar, warum du das Ausschneiden erst innerhalb der Schleife machst und nicht schon beim Hinzufügen.
(Mir ist immer noch nicht klar, wo die Iteration sein soll, die gleichzeitig über eine Liste iteriert und diese verändert, allerdings ist das mit einer Lösung mit ``multiprocessing`` auch nicht wichtig...)
Edit: Außerdem sollte deine try..except wirklich nur die Exception abfangen, dass die Queue leer ist. Man sollte nie allgemein ``Exception`` abfangen, und vor allem nicht über so einen langen Codeblock. Es gibt ja auch noch try..except..else
Edit2: ``class multiprocessing.JoinableQueue`` wär vielleicht auch sinnvoll einzusetzen.
@ ice2k3
Erstmal Danke für Deine Bemühungen. Ich muss erstmal nen Gang zurückfahren. Folgendes:
Wir haben - siehe oben - bereits den Kontext gewechselt. D.h. ich habe oben bereits geschrieben, dass ich folgende Lösung habe. Diese hat mit
der Frage an sich eher wenig gemein, denn diese Lösung basiert auf einem
ganz anderen Ansatz. Sorry wenn wir uns hier missverstanden habe.
Nun zu Deinen Aussagen:
gibt so etwas wie Latenzen.
an. siehe: _handle_tasks()
Es gibt in python viele verschieden Ansätze für ein und das selbe Problem.
Das ist ja auch der Vorteil. Ich glaube nicht, dass mein Code in irgendeiner Form komisch ist. Da gegenüber ist eine Geisterfahrt auf der A2 sicher aufregender.
Sorry für die Missverständnisse.
VG., Chris
Erstmal Danke für Deine Bemühungen. Ich muss erstmal nen Gang zurückfahren. Folgendes:
Wir haben - siehe oben - bereits den Kontext gewechselt. D.h. ich habe oben bereits geschrieben, dass ich folgende Lösung habe. Diese hat mit
der Frage an sich eher wenig gemein, denn diese Lösung basiert auf einem
ganz anderen Ansatz. Sorry wenn wir uns hier missverstanden habe.
Nun zu Deinen Aussagen:
Ja, ganz sicher.Du redest hier im Kontext von Threads und Prozessen, als wären sie das selbe. Ich hoffe dir ist bewusst, dass das nicht so ist.
Nein nicht immer wenn Du auf Netztwerkebene arbeitest dannIn diesem Zusammenhang sollte noch was gesagt werden: Eine Multithreading-Anwendung mit Python bringt *keine*
Performance-Vorteile.
gibt so etwas wie Latenzen.
Welche Auswirkungen der GIL (CPython) hat ist mir nicht neu.Im Gegenteil hat man durch den GIL sogar noch Overhead.
Da liegt genau der Haken, da synchron. Sieh dir bitte mal den LaderUm mit Python und einem Multicore Performance-Vorteile zu erziehlen, gibt es das Modul ``multiprocessing``. In dem Modul gibt es z.B. auch schon die Klasse ``Queue``.
an. siehe: _handle_tasks()
Diese seltsamen Konstrukte werden in 'multiprocessing' auch benutzt.seltsamen Konstrukte wie beschrieben und gezeigt zurückgreifen zu müssen.
Es gibt in python viele verschieden Ansätze für ein und das selbe Problem.
Das ist ja auch der Vorteil. Ich glaube nicht, dass mein Code in irgendeiner Form komisch ist. Da gegenüber ist eine Geisterfahrt auf der A2 sicher aufregender.
Sorry für die Missverständnisse.
VG., Chris
be or not to be
"Synchron" bedeutet in diesem Zusammenhang, dass die Queue Thread- und Prozesssicher ist. Genau das, was du benötigst! Du kannst trotzdem parallel mit Objekten, die du vom Queue geholt hast, operieren.maxwell hat geschrieben:Da liegt genau der Haken, da synchron. Sieh dir bitte mal den Lader
an. siehe: _handle_tasks()
Lader ??
_handle_tasks() ??
Sicher gibt es viele Möglichkeiten um ein Ziel zu erreichen, aber einige davon sind halt einfacher, übersichtlicher und wartbarer. Du haust ja auch nicht mit einer Axt ein Stück vom Brotlaib, nur weil man das machen könnte.
Edit: Mir ist immer noch nicht klar, was du genau unter "asynchron" verstehst. Ich denke, da steckt auch der Knackpunkt. Bitte mal ein kurzes Codebeispiel. Was sind die verschiedenen Prozesse bzw. Funktionen und von was hängen diese ab und wie sollen diese "asynchron" aufgerufen werden.