简体   繁体   中英

Does a multiprocessing.Lock pause the program within its context?

I want to know if the GIL Lock class pauses the program or skips the context within it in case the lock is held by another thread

from multiprocessing import Lock
from threading import Thread
import pandas as pd

# Thread 1
def th1(lock1):
    while True:
        with lock1:  # does the program pause/wait here in case lock is held by Th2 or simply skip the context within lock1?
            df1 = pd.read_csv('foo.csv')
        # do some work with df1

# Thread 2
def th2(lock2):
    while True:
        with lock2:  # does the program pause/wait here in case lock is held by Th1 or simply skip the context within lock2?
            df2 = pd.read_csv('foo.csv')
        # do some work with df2

if __name__ == "__main__":

    th_lock = Lock()
    th1_th = Thread(target=th1, daemon=False, kwargs:{'lock1':th_lock}
    th2_th = Thread(target=th2, daemon=False, kwargs:{'lock2':th_lock}
    th1_th.start()
    th2_th.start()

The Simple Answer

If you use a Lock in a with statement, it will block the thread until the lock is acquired and then will execute the suite:

with some_lock:
    do_all_the_things() 

If you want to peek at the lock, you can do the acquire manually and only execute the locked code if it succeeds

if some_lock.acquire(block=False):
    try:
        do_all_the_things() # only executed if lock acquired immediately
    finally:
        some_lock.release()

or, for a timeout

if some_lock.acquire(timeout=4.2):
    try:
        do_all_the_things() # only executed if lock acquired before timeout
    finally:
        some_lock.release()

The Complicated Answer

The steps for getting the lock differ by operating system but the general steps are

  • try to get the lock
  • on sucess, return
  • release the gil
  • wait for the lock
  • acquire the gil
  • return

The first entity that acquires the lock continues executing, without any change to the GIL. It has the GIL at the lock (or it wouldn't be running to get the lock) and will release it at the regular check interval to let other threads run.

Now a different thread is running and tries to get the lock. That operation releases the GIL and then waits for the lock. Since the first entity wasn't blocked except for waiting for the GIL, it runs again and finishes its business. When it finally gets around to releasing the lock, the second entity's non-GIL C code runs just a little bit to try to get the GIL. But its stuck there because the first entity still has the GIL.

The first entity will terminate or release the GIL at the regular check interval, letting the second entry run within the lock protected code.

Notice that neither the first or second entity is blocked. They will interleave based on when the other releases the GIL. Suppose you are trying to protect a data structure in the lock. Well, the other code is running. If it fiddles with the same data outside of the lock, you've got a bug. The lock was useless. This is cooperative locking. It only works if everyone plays the game.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM