harlowja / fasteners

A python package that provides useful locks.
Apache License 2.0
248 stars 45 forks source link

Add usage examples to readme #58

Closed psarka closed 3 years ago

psarka commented 3 years ago

@harlowja, I need your input on the API and general goals of fasteners lib. I was writing a better README file, and realized, that the thread part of fasteners does something else than I thought :)

Here are the parts that I understand:

  1. Fasteners provides a Readers Writer lock for threads, and (as of last week) a Readers Writer lock for processes. They both have the same API and a very clean feature set:
rw_lock = fasteners.ReaderWriterLock()                                 # for threads
rw_lock = fasteners.InterProcessReaderWriterLock('path/to/lock.file')  # for processes

with rw_lock.write_locked():
    ... # write_to_resource

with rw_lock.read_locked():
    ... # read_from_resource
  1. Fasteners provides a simple Lock for processes. It has no equivalent for threads, presumably because thread Lock is part of the standard library, so there is no point in duplicating it.
lock = threading.Lock()                                 # for threads
lock = fasteners.InterProcessLock('path/to/lock.file')  # for processes

with lock:
    ... # exclusive access to resource
  1. Fasteners provides some sugar, which one can use to replace with statements by a decorator. On the process side this looks like this (read & write are implemented by me, emulating the simple lock):
    
    @fasteners.interprocess_locked('path/to/lock.file')
    def exclusive_access_to_resource():
    ...

@fasteners.interprocess_read_locked('path/to/lock.file') def read_access_to_resource(): ...

@fasteners.interprocess_write_locked('path/to/lock.file') def write_access_to_resource(): ...


Here is the part I don't understand:

1. By symmetry, I was expecting decorators for tread locks to work in the same way. That is:

```python
@fasteners.locked('lock_name')
def exclusive_access_to_resource():
    ...

@fasteners.read_locked('lock_name')
def read_access_to_resource():
    ...

@fasteners.write_locked('lock_name')
def write_access_to_resource():
    ...

But they don't. Instead, the thread side decorators only work on class methods (rather than standalone functions), and furthermore, they have to refer by a string argument to an attribute of an instance that contains a regular threading.Lock.

Could you expand a bit on this? Is this a specific requirement by the upstream projects? Would it make sense to migrate to a cleaner API that is used by process locks?

psarka commented 3 years ago

I thought about this more, and propose to approach this as follows:

Let's consider the locks themselves (with regular and contextmanager APIs) as the main assets of this library, and let's keep the decorators as they are for backwards compatibility. As they are not consistent, let's not highlight them in the readme, and instead focus on the main features of the locks.

I added quite some information about the locks that we provide in the readme, if you have time, please take a look (otherwise I'll merge this after a while).

(The rendered README is easier to read than the diff: https://github.com/harlowja/fasteners/tree/better-readme)

harlowja commented 3 years ago

Hi ya, just got back from vacation, will look at soon. I am fine with with regular and contextmanager APIs as the main assets makes sense to me.

harlowja commented 3 years ago

Maybe someday if https://bugs.python.org/issue8800 happens we can also eliminate some code from this library :-P