Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c801ad3

Browse files
committed
merge heads
2 parents 3ed559a + b528fcf commit c801ad3

5 files changed

Lines changed: 46 additions & 7 deletions

File tree

Lib/multiprocessing/pool.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,11 @@ def map_async(self, func, iterable, chunksize=None, callback=None,
321321

322322
@staticmethod
323323
def _handle_workers(pool):
324-
while pool._worker_handler._state == RUN and pool._state == RUN:
324+
thread = threading.current_thread()
325+
326+
# Keep maintaining workers until the cache gets drained, unless the pool
327+
# is terminated.
328+
while thread._state == RUN or (pool._cache and thread._state != TERMINATE):
325329
pool._maintain_pool()
326330
time.sleep(0.1)
327331
# send sentinel to stop workers

Lib/test/test_multiprocessing.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,6 +1266,20 @@ def test_pool_worker_lifetime(self):
12661266
p.close()
12671267
p.join()
12681268

1269+
def test_pool_worker_lifetime_early_close(self):
1270+
# Issue #10332: closing a pool whose workers have limited lifetimes
1271+
# before all the tasks completed would make join() hang.
1272+
p = multiprocessing.Pool(3, maxtasksperchild=1)
1273+
results = []
1274+
for i in range(6):
1275+
results.append(p.apply_async(sqr, (i, 0.3)))
1276+
p.close()
1277+
p.join()
1278+
# check the results
1279+
for (j, res) in enumerate(results):
1280+
self.assertEqual(res.get(), sqr(j))
1281+
1282+
12691283
#
12701284
# Test that manager has expected number of shared objects left
12711285
#

Misc/NEWS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ What's New in Python 3.3 Alpha 1?
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #13018: Fix reference leaks in error paths in dictobject.c.
14+
Patch by Suman Saha.
15+
1316
- Issue #13201: Define '==' and '!=' to compare range objects based on
1417
the sequence of values they define (instead of comparing based on
1518
object identity).
@@ -338,6 +341,9 @@ Core and Builtins
338341
Library
339342
-------
340343

344+
- Issue #10332: multiprocessing: fix a race condition when a Pool is closed
345+
before all tasks have completed.
346+
341347
- Issue #13255: wrong docstrings in array module.
342348

343349
- Issue #8540: Remove deprecated Context._clamp attribute in Decimal module.

Objects/dictobject.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,14 +1314,18 @@ dict_fromkeys(PyObject *cls, PyObject *args)
13141314
PyObject *key;
13151315
Py_hash_t hash;
13161316

1317-
if (dictresize(mp, Py_SIZE(seq)))
1317+
if (dictresize(mp, Py_SIZE(seq))) {
1318+
Py_DECREF(d);
13181319
return NULL;
1320+
}
13191321

13201322
while (_PyDict_Next(seq, &pos, &key, &oldvalue, &hash)) {
13211323
Py_INCREF(key);
13221324
Py_INCREF(value);
1323-
if (insertdict(mp, key, hash, value))
1325+
if (insertdict(mp, key, hash, value)) {
1326+
Py_DECREF(d);
13241327
return NULL;
1328+
}
13251329
}
13261330
return d;
13271331
}
@@ -1332,14 +1336,18 @@ dict_fromkeys(PyObject *cls, PyObject *args)
13321336
PyObject *key;
13331337
Py_hash_t hash;
13341338

1335-
if (dictresize(mp, PySet_GET_SIZE(seq)))
1339+
if (dictresize(mp, PySet_GET_SIZE(seq))) {
1340+
Py_DECREF(d);
13361341
return NULL;
1342+
}
13371343

13381344
while (_PySet_NextEntry(seq, &pos, &key, &hash)) {
13391345
Py_INCREF(key);
13401346
Py_INCREF(value);
1341-
if (insertdict(mp, key, hash, value))
1347+
if (insertdict(mp, key, hash, value)) {
1348+
Py_DECREF(d);
13421349
return NULL;
1350+
}
13431351
}
13441352
return d;
13451353
}

Python/import.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -938,12 +938,19 @@ make_compiled_pathname(PyObject *pathstr, int debug)
938938
Py_ssize_t pycache_len = sizeof(CACHEDIR) - 1;
939939
int kind;
940940
void *data;
941+
Py_UCS4 lastsep;
941942

942943
/* Compute the output string size. */
943944
len = PyUnicode_GET_LENGTH(pathstr);
944945
/* If there is no separator, this returns -1, so
945-
lastsep will be 0. */
946+
fname will be 0. */
946947
fname = rightmost_sep_obj(pathstr, 0, len) + 1;
948+
/* Windows: re-use the last separator character (/ or \\) when
949+
appending the __pycache__ path. */
950+
if (fname > 0)
951+
lastsep = PyUnicode_READ_CHAR(pathstr, fname -1);
952+
else
953+
lastsep = SEP;
947954
ext = fname - 1;
948955
for(i = fname; i < len; i++)
949956
if (PyUnicode_READ_CHAR(pathstr, i) == '.')
@@ -965,7 +972,7 @@ make_compiled_pathname(PyObject *pathstr, int debug)
965972
pos = fname;
966973
for (i = 0; i < pycache_len; i++)
967974
PyUnicode_WRITE(kind, data, pos++, CACHEDIR[i]);
968-
PyUnicode_WRITE(kind, data, pos++, SEP);
975+
PyUnicode_WRITE(kind, data, pos++, lastsep);
969976
PyUnicode_CopyCharacters(result, pos, pathstr,
970977
fname, ext - fname);
971978
pos += ext - fname;

0 commit comments

Comments
 (0)