473,394 Members | 1,944 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,394 software developers and data experts.

can't delete from a dictionary in a loop

This might be more information than necessary, but it's the best way I
can think of to describe the question without being too vague.

The task:

I have a list of processes (well, strings to execute said processes)
and I want to, roughly, keep some number N running at a time. If one
terminates, I want to start the next one in the list, or otherwise,
just wait.

The attempted solution:

Using subprocess, I Popen the next executable in the list, and store
it in a dictionary, with keyed on the pid:
(outside the loop)
procs_dict={}

(inside a while loop)
process = Popen(benchmark_exstring[num_started], shell=true)
procs_dict[process.pid]=process

Then I sleep for a while, then loop through the dictionary to see
what's terminated. For each one that has terminated, I decrement a
counter so I know how many to start next time, and then try to remove
the record from the dictionary (since there's no reason to keep
polling it since I know it's terminated). Roughly:

for pid in procs_dict:
if procs_dict[pid].poll() != None
# do the counter updates
del procs_dict[pid]

The problem:

RuntimeError: dictionary changed size during iteration

So, the question is: is there a way around this? I know that I can
just /not/ delete from the dictionary and keep polling each time
around, but that seems sloppy and like it could keep lots of memory
around that I don't need, since presumably the dictionary holding a
reference to the Popen object means the garbage collector could never
reclaim it. Is the only reasonable solution to do something like
append all of those pids to a list, and then after I've iterated over
the dictionary, iterate over the list of pids to delete?

(Also, from the implementation side, is there a reason the dictionary
iterator can't deal with that? If I was deleting from in front of the
iterator, maybe, but since I'm deleting from behind it...)
Jun 27 '08 #1
11 2616
Dan Upton wrote:
for pid in procs_dict:
if procs_dict[pid].poll() != None
# do the counter updates
del procs_dict[pid]

The problem:

RuntimeError: dictionary changed size during iteration
I don't know if the setup with the pids in a dictionary is the best way to
manage a pool of processes... I'll leave it others, presumably more
knowledgable, to comment on that. :-) But I can tell you how to solve the
immediate problem:

for pid in procs_dict.keys():
...

Hope this helps!

--Hans
Jun 27 '08 #2
On 16 mai, 23:28, Hans Nowak <zephyrfalcon!NO_SP...@gmail.comwrote:
Dan Upton wrote:
for pid in procs_dict:
if procs_dict[pid].poll() != None
# do the counter updates
del procs_dict[pid]
The problem:
RuntimeError: dictionary changed size during iteration

I don't know if the setup with the pids in a dictionary is the best way to
manage a pool of processes... I'll leave it others, presumably more
knowledgable, to comment on that. :-) But I can tell you how to solve the
immediate problem:

for pid in procs_dict.keys():
I'm afraid this will do the same exact thing. A for loop on a dict
iterates over the dict keys, so both statements are strictly
equivalent from a practical POV.
Jun 27 '08 #3
On 16 mai, 23:34, "bruno.desthuilli...@gmail.com"
<bruno.desthuilli...@gmail.comwrote:
On 16 mai, 23:28, Hans Nowak <zephyrfalcon!NO_SP...@gmail.comwrote:

Dan Upton wrote:
for pid in procs_dict:
(snip)
for pid in procs_dict.keys():

I'm afraid this will do the same exact thing. A for loop on a dict
iterates over the dict keys, so both statements are strictly
equivalent from a practical POV.
Hem. Forget it. I should think twice before posting - this will
obviously make a big difference here. Sorry for the noise.

Jun 27 '08 #4
br*****************@gmail.com wrote:
On 16 mai, 23:28, Hans Nowak <zephyrfalcon!NO_SP...@gmail.comwrote:
>Dan Upton wrote:
>>for pid in procs_dict:
if procs_dict[pid].poll() != None
# do the counter updates
del procs_dict[pid]

The problem:

RuntimeError: dictionary changed size during iteration
I don't know if the setup with the pids in a dictionary is the best way to
manage a pool of processes... I'll leave it others, presumably more
knowledgable, to comment on that. :-) But I can tell you how to solve the
immediate problem:

for pid in procs_dict.keys():
No, keys() produces a list (which is what is wanted here).

It's iterkeys() that produces an iterator which would reproduce the OP's
problem.

And then, in Python3, keys() produces something else altogether (call a
view of the dictionary) which would provoke the same problem, so yet
another solution would have to be found then.

Gary Herron
>
I'm afraid this will do the same exact thing. A for loop on a dict
iterates over the dict keys, so both statements are strictly
equivalent from a practical POV.
--
http://mail.python.org/mailman/listinfo/python-list
Jun 27 '08 #5
br*****************@gmail.com wrote:
On 16 mai, 23:34, "bruno.desthuilli...@gmail.com"
<bruno.desthuilli...@gmail.comwrote:
>On 16 mai, 23:28, Hans Nowak <zephyrfalcon!NO_SP...@gmail.comwrote:

>>Dan Upton wrote:
for pid in procs_dict:
(snip)
>> for pid in procs_dict.keys():
I'm afraid this will do the same exact thing. A for loop on a dict
iterates over the dict keys, so both statements are strictly
equivalent from a practical POV.

Hem. Forget it. I should think twice before posting - this will
obviously make a big difference here. Sorry for the noise.
:-) It appears that you would be right if this was Python 3.0, though:

Python 3.0a5 (r30a5:62856, May 16 2008, 11:43:33)
[GCC 4.0.1 (Apple Computer, Inc. build 5367)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>d = {1: 2, 3: 4, 5: 6}
for i in d.keys(): del d[i]
....
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration

Maybe 'for i in d' and 'for i in d.keys()' *are* functionally equivalent in 3.0,
as d.keys() returns an object that iterates over d's keys... but I haven't read
enough about it yet to be sure. In any case, the problem goes away when we
force a list:
>>d = {1: 2, 3: 4, 5: 6}
for i in list(d.keys()): del d[i]
....
>>d
{}

--Hans
Jun 27 '08 #6
On May 16, 4:51*pm, Hans Nowak <zephyrfalcon!NO_SP...@gmail.com>
wrote:
bruno.desthuilli...@gmail.com wrote:
On 16 mai, 23:34, "bruno.desthuilli...@gmail.com"
<bruno.desthuilli...@gmail.comwrote:
On 16 mai, 23:28, Hans Nowak <zephyrfalcon!NO_SP...@gmail.comwrote:
>Dan Upton wrote:
for pid in procs_dict:
(snip)
>* *for pid in procs_dict.keys():
I'm afraid this will do the same exact thing. A for loop on a dict
iterates over the dict keys, so both statements are strictly
equivalent from a practical POV.
Hem. Forget it. I should think twice before posting - this will
obviously make a big difference here. *Sorry for the noise.

:-) *It appears that you would be right if this was Python 3.0, though:

Python 3.0a5 (r30a5:62856, May 16 2008, 11:43:33)
[GCC 4.0.1 (Apple Computer, Inc. build 5367)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
*>>d = {1: 2, 3: 4, 5: 6}
*>>for i in d.keys(): del d[i]
...
Traceback (most recent call last):
* *File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration

Maybe 'for i in d' and 'for i in d.keys()' *are* functionally equivalent in 3.0,
as d.keys() returns an object that iterates over d's keys... but I haven'tread
enough about it yet to be sure. *In any case, the problem goes away whenwe
force a list:

*>>d = {1: 2, 3: 4, 5: 6}
*>>for i in list(d.keys()): del d[i]
...
*>>d
{}

--Hans- Hide quoted text -

- Show quoted text -
You may be searching for:

for i in d.keys()[:]:
del d[ i ]

Jun 27 '08 #7
On Fri, May 16, 2008 at 6:40 PM, Gary Herron <gh*****@islandtraining.comwrote:
br*****************@gmail.com wrote:
>>
On 16 mai, 23:28, Hans Nowak <zephyrfalcon!NO_SP...@gmail.comwrote:
>>>
Dan Upton wrote:
for pid in procs_dict:
if procs_dict[pid].poll() != None
# do the counter updates
del procs_dict[pid]
The problem:
RuntimeError: dictionary changed size during iteration
I don't know if the setup with the pids in a dictionary is the best way
to
manage a pool of processes... I'll leave it others, presumably more
knowledgable, to comment on that. :-) But I can tell you how to solve
the
immediate problem:

for pid in procs_dict.keys():

No, keys() produces a list (which is what is wanted here).
It's iterkeys() that produces an iterator which would reproduce the OP's
problem.

And then, in Python3, keys() produces something else altogether (call a view
of the dictionary) which would provoke the same problem, so yet another
solution would have to be found then.
In Python 3.0, list(procs_dict.keys()) would have the same effect.
Gary Herron
>>
I'm afraid this will do the same exact thing. A for loop on a dict
iterates over the dict keys, so both statements are strictly
equivalent from a practical POV.
--
http://mail.python.org/mailman/listinfo/python-list

--
http://mail.python.org/mailman/listinfo/python-list


--
Eduardo de Oliveira Padoan
http://www.advogato.org/person/eopadoan/
http://twitter.com/edcrypt
Bookmarks: http://del.icio.us/edcrypt
Jun 27 '08 #8
On May 16, 10:22 pm, "Dan Upton" <up...@virginia.eduwrote:
This might be more information than necessary, but it's the best way I
can think of to describe the question without being too vague.

The task:

I have a list of processes (well, strings to execute said processes)
and I want to, roughly, keep some number N running at a time. If one
terminates, I want to start the next one in the list, or otherwise,
just wait.

The attempted solution:

Using subprocess, I Popen the next executable in the list, and store
it in a dictionary, with keyed on the pid:
(outside the loop)
procs_dict={}

(inside a while loop)
process = Popen(benchmark_exstring[num_started], shell=true)
procs_dict[process.pid]=process

Then I sleep for a while, then loop through the dictionary to see
what's terminated. For each one that has terminated, I decrement a
counter so I know how many to start next time, and then try to remove
the record from the dictionary (since there's no reason to keep
polling it since I know it's terminated). Roughly:

for pid in procs_dict:
if procs_dict[pid].poll() != None
# do the counter updates
del procs_dict[pid]

The problem:

RuntimeError: dictionary changed size during iteration

So, the question is: is there a way around this? I know that I can
just /not/ delete from the dictionary and keep polling each time
around, but that seems sloppy and like it could keep lots of memory
around that I don't need, since presumably the dictionary holding a
reference to the Popen object means the garbage collector could never
reclaim it. Is the only reasonable solution to do something like
append all of those pids to a list, and then after I've iterated over
the dictionary, iterate over the list of pids to delete?

(Also, from the implementation side, is there a reason the dictionary
iterator can't deal with that? If I was deleting from in front of the
iterator, maybe, but since I'm deleting from behind it...)
Why do you need a counter? len(procs_dict) will tell you how many are
in the dictionary.

You can rebuild the dictionary, excluding those that are no longer
active, with:

procs_dict = dict((id, process) for id, process in
procs_dict.iteritems() if process.poll() != None)

and then start N - len(procs_dict) new processes.
Jun 27 '08 #9
On May 16, 5:22*pm, "Dan Upton" <up...@virginia.eduwrote:
This might be more information than necessary, but it's the best way I
can think of to describe the question without being too vague.

The task:

I have a list of processes (well, strings to execute said processes)
and I want to, roughly, keep some number N running at a time. *If one
terminates, I want to start the next one in the list, or otherwise,
just wait.

The attempted solution:

Using subprocess, I Popen the next executable in the list, and store
it in a dictionary, with keyed on the pid:
(outside the loop)
procs_dict={}

(inside a while loop)
process = Popen(benchmark_exstring[num_started], shell=true)
procs_dict[process.pid]=process

Then I sleep for a while, then loop through the dictionary to see
what's terminated. *For each one that has terminated, I decrement a
counter so I know how many to start next time, and then try to remove
the record from the dictionary (since there's no reason to keep
polling it since I know it's terminated). *Roughly:

for pid in procs_dict:
* if procs_dict[pid].poll() != None
* *# do the counter updates
* *del procs_dict[pid]
Since you don't look up processes by pid, you don't need a dictionary
here. A cleaner and efficient solution is use a deque to pop processes
from one end and push them to the other if still alive, something like
this:

from collections import deque

processes = deque()
# start processes and put them in the queue

while processes:
for i in xrange(len(processes)):
p = processes.pop()
if p.poll() is None: # not finished yet
processes.append_left(p)
time.sleep(5)
HTH,
George
Jun 27 '08 #10
On May 17, 3:06*am, George Sakkis <george.sak...@gmail.comwrote:
On May 16, 5:22*pm, "Dan Upton" <up...@virginia.eduwrote:


This might be more information than necessary, but it's the best way I
can think of to describe the question without being too vague.
The task:
I have a list of processes (well, strings to execute said processes)
and I want to, roughly, keep some number N running at a time. *If one
terminates, I want to start the next one in the list, or otherwise,
just wait.
The attempted solution:
Using subprocess, I Popen the next executable in the list, and store
it in a dictionary, with keyed on the pid:
(outside the loop)
procs_dict={}
(inside a while loop)
process = Popen(benchmark_exstring[num_started], shell=true)
procs_dict[process.pid]=process
Then I sleep for a while, then loop through the dictionary to see
what's terminated. *For each one that has terminated, I decrement a
counter so I know how many to start next time, and then try to remove
the record from the dictionary (since there's no reason to keep
polling it since I know it's terminated). *Roughly:
for pid in procs_dict:
* if procs_dict[pid].poll() != None
* *# do the counter updates
* *del procs_dict[pid]

Since you don't look up processes by pid, you don't need a dictionary
here. A cleaner and efficient solution is use a deque to pop processes
from one end and push them to the other if still alive, something like
this:

from collections import deque

processes = deque()
# start processes and put them in the queue

while processes:
* * for i in xrange(len(processes)):
* * * * p = processes.pop()
* * * * if p.poll() is None: # not finished yet
* * * * * * processes.append_left(p)
* * time.sleep(5)

HTH,
George- Hide quoted text -

- Show quoted text -
No underscore in appendleft.
Jun 27 '08 #11
Eduardo O. Padoan wrote:
On Fri, May 16, 2008 at 6:40 PM, Gary Herron <gh*****@islandtraining.comwrote:
>br*****************@gmail.com wrote:
>>On 16 mai, 23:28, Hans Nowak <zephyrfalcon!NO_SP...@gmail.comwrote:

Dan Upton wrote:
<<asking about iterating over a dictionary and deleting elements>>
>>>...to solve the immediate problem:
for pid in procs_dict.keys():
And then, in Python3, keys() produces something else altogether (call a view
of the dictionary) which would provoke the same problem, so yet another
solution would have to be found then.
In Python 3.0, list(procs_dict.keys()) would have the same effect.
Or (simpler in either 3.0 or 2.X):
for pid in list(procs_dict):
...

--Scott David Daniels
Sc***********@Acm.Org
Jun 27 '08 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: kbass | last post by:
I am new to Python and I am attempting to retrieve data from a database and I would like to place this data into a nested dictionary. After placing the data into a dictionary, I would like to loop...
11
by: Egor Bolonev | last post by:
saluton al ciuj i know how to get item by key ================== dict = {10 : 50, 2 : 12, 4 : 43} print dict >> 12
2
by: techiepundit | last post by:
I'm parsing some data of the form: OuterName1 InnerName1=5,InnerName2=7,InnerName3=34; OuterName2 InnerNameX=43,InnerNameY=67,InnerName3=21; OuterName3 .... and so on.... These are fake...
10
by: Ben | last post by:
Hello... I have set up a dictionary into whose values I am putting a list. I loop around and around filling my list each time with new values, then dumping this list into the dictionary. Or so I...
4
by: O.B. | last post by:
I need the ability to parse through the values of a Dictionary and remove certain ones depending on their attribute values. In the example below, an InvalidOperationException is thrown in the...
4
by: etuncer | last post by:
Hello All, I have Access 2003, and am trying to build a database for my small company. I want to be able to create a word document based on the data entered through a form. the real question is...
18
by: Marko.Cain.23 | last post by:
Hi, I create a dictionary like this myDict = {} and I add entry like this: myDict = 1 but how can I empty the whole dictionary? Thank you.
1
by: Peter | last post by:
Hi, I have a Dictionary<key, valuewhich is accessed by three threads. One thread puts my value objects in the dictionary (occasionally), and also updates the contents of existing value objects -...
0
by: Gary Herron | last post by:
Dan Upton wrote: Yes. Create a list of keys, and loop through it: pids = procs_dict.keys() for pid in pids: if procs_dict.poll() != None # do the counter updates del procs_dict Then the...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.