Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-35813: Added shared_memory submodule of multiprocessing. #11664

Merged
merged 8 commits into from
Feb 2, 2019

Conversation

applio
Copy link
Member

@applio applio commented Jan 24, 2019

Tests and docs are still absent. Some cleanup remains to be done in the code as well but all appears to be functional and stable across platforms since the sprint in September 2018.

https://bugs.python.org/issue35813


def __init__(self, name, flags=None, mode=None, size=None, read_only=False):
if name is None:
name = f'wnsm_{os.getpid()}_{random.randrange(100000)}'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

random.randrange(100000)
Why use a random number here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the user does not supply a name for the shared memory segment, an attempt is made to create a hopefully unique name. There are system-imposed constraints on the length of the name used and (I believe) the use of only ascii characters in the name but the use of a number here is not a requirement. Are you thinking about suggesting a mixture of letters and numbers?
An accidental collision with an existing shared memory segment's name would likely result in unintended/undesirable behavior.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't using a UUID give better uniqueness here, or just using itertools.count() instead of a random renumber to number memory segments? The latter avoids conflicts in a single process, although there still might be conflicts between processes when old segments aren't cleaned up properly.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced by Neil's patch with a stronger solution in GH-11816.

@applio applio merged commit e5ef45b into python:master Feb 2, 2019
@bedevere-bot
Copy link

@applio: Please replace # with GH- in the commit message next time. Thanks!

@bedevere-bot
Copy link

⚠️⚠️⚠️ Buildbot failure ⚠️⚠️⚠️

Hi! The buildbot AMD64 FreeBSD 10-STABLE Non-Debug 3.x has failed when building commit e5ef45b.

What do you need to do:

  1. Don't panic.
  2. Check the buildbot page in the devguide if you don't know what the buildbots are or how they work.
  3. Go to the page of the buildbot that failed (https://buildbot.python.org/all/#builders/167/builds/531) and take a look at the build logs.
  4. Check if the failure is related to this commit (e5ef45b) or if it is a false positive.
  5. If the failure is related to this commit, please, reflect that on the issue and make a new Pull Request with a fix.

You can take a look at the buildbot page here:

https://buildbot.python.org/all/#builders/167/builds/531

Click to see traceback logs
Traceback (most recent call last):
  File "/usr/home/buildbot/python/3.x.koobs-freebsd10.nondebug/build/Lib/test/_test_multiprocessing.py", line 1866, in test_default_timeout
    self.assertEqual(len(results), barrier.parties)
AssertionError: 0 != 5

----------------------------------------------------------------------

Ran 324 tests in 348.271s

FAILED (failures=1, skipped=32)

Copy link
Contributor

@ronaldoussoren ronaldoussoren left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't reviewed most of the Python code, due to lack of documentation it is unclear what the intended behaviour of of the code is.


def __init__(self, name, flags=None, mode=None, size=None, read_only=False):
if name is None:
name = f'wnsm_{os.getpid()}_{random.randrange(100000)}'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't using a UUID give better uniqueness here, or just using itertools.count() instead of a random renumber to number memory segments? The latter avoids conflicts in a single process, although there still might be conflicts between processes when old segments aren't cleaned up properly.

pass


class PosixSharedMemory(_PosixSharedMemory):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this class defined unconditionally when it relies on functionality from an optional C extension. I'd leave the class out entirely when running on platform that doesn't support the C extension because that makes it clearer that functionality is not present.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in GH-11816.

self.close_fd()


class SharedMemory:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally don't like this pattern. This is basically a function call, and could also just be an alias. Something like:

if os.name == 'nt':
    SharedMemory = WindowsSharedMemory
else:
    SharedMemory = PosixSharedMemory

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in GH-11816.

)
return f"{self.__class__.__name__}({', '.join(formatted_pairs)})"

#def __getstate__(self):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is commented-out code and should be removed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in GH-11816.

packing format for any storable value must require no more than 8
characters to describe its format."""

# TODO: Adjust for discovered word size of machine.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please actually adjust for different word sizes, if needed (another option is to require that the size of the C double is 8 bytes and that a 64-bit integer type is used for integers).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment was moot and now removed in GH-11816.

PyObject *module;
PyObject *module_dict;

// I call this in case I'm asked to create any random names.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changes process global state. Please remove.

Furthermore creating random names in C code isn't needed anyway (see one of the earlier comments)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in GH-11816.

PyModule_AddObject(module, "_PosixSharedMemory", (PyObject *)&SharedMemoryType);


PyModule_AddStringConstant(module, "__copyright__", "Copyright 2012 Philip Semanchuk, 2018-2019 Davin Potts");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only other files with a copyright attribute are parser, optparse and platform. I'd prefer to avoid adding new copyright attributes to stdlib modules.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment on issue.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in 7c65017 which should appear in GH-11816 shortly.

I have pinged Van again asking for verification that this is indeed appropriate but I have made the change in anticipation that this is all good.

PyModule_AddIntConstant(module, "O_EXCL", O_EXCL);
PyModule_AddIntConstant(module, "O_CREX", O_CREAT | O_EXCL);
PyModule_AddIntConstant(module, "O_TRUNC", O_TRUNC);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These values are already attributes of the os module, don't add them to this module as well.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in GH-11816.

else
PyDict_SetItemString(module_dict, "Error", pBaseException);

if (!(pPermissionsException = PyErr_NewException("_posixshmem.PermissionsError", pBaseException, NULL)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use PermissionsError instead of a specific error?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to using PermissionsError. I used a custom error in the original code for Python 2.x support.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed in GH-11816.

else
PyDict_SetItemString(module_dict, "PermissionsError", pPermissionsException);

if (!(pExistentialException = PyErr_NewException("_posixshmem.ExistentialError", pBaseException, NULL)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use FileNotFoundError instead of a specific exception?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed in GH-11816.

assert hasattr(self, "_proxied_type")
try:
existing_type.__init__(self, *args, **kwargs)
except:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bare except clause should be avoided (use except Exception: instead)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed! I have changed this in a097dbb as part of PR-11816.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants