473,791 Members | 3,193 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

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 2652
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!N O_SP...@gmail.c omwrote:
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.desthuil li...@gmail.com "
<bruno.desthuil li...@gmail.com wrote:
On 16 mai, 23:28, Hans Nowak <zephyrfalcon!N O_SP...@gmail.c omwrote:

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!N O_SP...@gmail.c omwrote:
>Dan Upton wrote:
>>for pid in procs_dict:
if procs_dict[pid].poll() != None
# do the counter updates
del procs_dict[pid]

The problem:

RuntimeErro r: 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.desthuil li...@gmail.com "
<bruno.desthuil li...@gmail.com wrote:
>On 16 mai, 23:28, Hans Nowak <zephyrfalcon!N O_SP...@gmail.c omwrote:

>>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!N O_SP...@gmail.c om>
wrote:
bruno.desthuill i...@gmail.com wrote:
On 16 mai, 23:34, "bruno.desthuil li...@gmail.com "
<bruno.desthuil li...@gmail.com wrote:
On 16 mai, 23:28, Hans Nowak <zephyrfalcon!N O_SP...@gmail.c omwrote:
>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*****@island training.comwro te:
br************* ****@gmail.com wrote:
>>
On 16 mai, 23:28, Hans Nowak <zephyrfalcon!N O_SP...@gmail.c omwrote:
>>>
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
knowledgabl e, 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.iter items() 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(proc esses)):
p = processes.pop()
if p.poll() is None: # not finished yet
processes.appen d_left(p)
time.sleep(5)
HTH,
George
Jun 27 '08 #10

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

Similar topics

2
2759
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 through the data using for loops. How would I do this? The format that I am attempting is: Select data ... Get data ... Place data into a nested dictionary Rev = for value1 in a:
11
10467
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
2018
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 names I've made up to illustrate the point more clearly. (the embedded device device can't produce XML and this is what I have
10
2343
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 thought... It would appear that what I am dumping into the dictionary value is only a pointer to the original list, so after all my iterations all I have is a dictionary whose every value is equal to that of the list the final time I looped...
4
34163
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 foreach statement when the first item is removed from the Dictionary. From looking at Dictionary's methods, I couldn't find anything to create a copy of the Values before starting the foreach loop. Help? static void someTest() {
4
12444
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 this: can Access create the document and place it as an OLE object to the relevant table? Any help is greatly appreciated. Ricky
18
2976
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
1890
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 - by finding the appropriate object via a key and updating the value (this updating happens several times a second). Another thread removes "dead" value objects from the dictionary (very occasionally)
0
2080
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 diction delete operation won't trip up the loop and its
0
9669
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9517
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
1
10156
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 Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9997
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 protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
9030
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7537
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
6776
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
2
3718
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2916
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

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.