了解Python中的多线程和锁(概念和示例)
我对使用它进行编程项目的多线程进行了研究(这里是第一名...)。如果您认为我的陈述在下面正确,或者对错误或需要更正的评论表示感谢,我将不胜感激。
- 锁定是一个可以通过引用传递给函数,方法的对象。然后,(在此示例中)函数可以使用该锁定对象引用,以便在数据上安全操作(此示例中的一个变量)。它通过获取锁,修改变量然后释放锁来实现此目的。
- 可以创建线程以定位一个函数,该功能可以获取对锁定的引用(然后实现上面所述的内容)。
- 锁确实不是保护特定变量,对象等。
- 除非获得(并释放),否则锁不会保护或做任何东西。
- 因此,为了实现所需的保护,锁定 使用 的责任。
- 如果在线程A执行的函数中获取锁目的。
- 仅当线程B的函数B想要获取相同锁定(即通过相同的引用锁定对象),该功能已经由螺纹A当时针对的功能获取,锁定锁定的锁在该线程中的两个线程上,b将停止进一步执行,直到螺纹A针对的功能再次释放锁。
- 因此,如果其目标函数想要(并等待)获取相同的锁定本身,则仅锁定锁才会停止执行线程。因此,通过螺纹获取锁定,它只能 防止线程B获得相同的锁,仅此而已。
如果我想在设置变量时使用锁来防止
- 比赛
- 条件在设置变量之前,每个函数和每个函数中的锁定(并在此之后发布)。 (*)
- 如果我只创建一个针对函数的线程而不提供对锁定对象的引用并设置变量的线程,或者
- 如果我通过其目标函数具有锁定的线程设置变量对象,但在操作之前没有获取它,我将失败以实现变量的线程安全设置。
(*)只要其他线程不能访问变量,就应获取锁定。现在,我想将其与数据库事务进行比较...我锁定数据库(〜获取锁定),直到我的指令集完成为止,然后我提交(〜释放锁定)。
示例如果我想创建一个成员_Value
的类:
class Version1:
def __init__(self):
self._value:int = 0
self._lock:threading.Lock = threading.Lock()
def getValue(self) -> int:
"""Getting won't be protected in this example."""
return self._value
def setValue(self, val:int) -> None:
"""This will be made thread-safe by member lock."""
with self._lock:
self._value = val
v1 = Version1()
t1_1 = threading.Thread(target=v1.setValue, args=(1)).start()
t1_2 = threading.Thread(target=v1.setValue, args=(2)).start()
class Version2:
def __init__(self):
self._value:int = 0
def getValue(self) -> int:
"""Getting won't be protected in this example."""
return self._value
def setValue(self, val:int, lock:threading.Lock) -> None:
"""This will be made thread-safe by injected lock."""
with self._lock:
self._value = val
v2 = Version2()
l = threading.Lock()
t2_1 = threading.Thread(target=v2.setValue, args=(1, l)).start()
t2_2 = threading.Thread(target=v2.setValue, args=(2, l)).start()
- 在
版本1
中,i作为类提供者,可以保证设置_value
始终是线程安全... - ...因为在
process2 ,我的班级用户可能会将不同的锁定对象传递给两个产卵线程,从而使锁定保护毫无用处。
- 如果我想为我的班级用户提供将
_Value
设置设置的自由,将应该以线程安全的方式执行的更大步骤集合,我可以注入lock
引用版本1
's__ INT __
功能,并将其分配给_lock
成员。因此,可以保证课程的线程安全操作,同时仍允许类的用户为此目的使用“她自己的”锁定。
现在,0-15的分数将评分我(MIS)理解锁的程度...:D
I did research on multi-threading for a programming project using it (first-timer here...). I would appreciate if you deemed my statements below correct or, rather, comment on the ones that are wrong or need correction.
- A lock is an object which can be passed to functions, methods, ... by reference. A (in this example) function can then make use of that lock object reference in order to safely operate on data (a variable in this example). It does this by acquiring the lock, modifying the variable and then releasing the lock.
- A thread can be created to target a function, which may obtain a reference to a lock (to then achieve what is stated above).
- A lock does not protect a specific variable, object etc.
- A lock does not protect or do anything unless it is acquired (and released).
- Thus, it is in the responsibility of the programmer to use the lock in order achieve the desired protection.
- If a lock is acquired inside a function executed by thread A, this has no immediate influence on any other running thread B. Not even if the functions targeted by threads A and B have a reference to the same lock object.
- Only if the function targeted by thread B wants to acquire the same lock (i.e. via the same referenced lock object), which already was acquired by the function targeted by thread A at that time, the lock conveys influence on both threads in that thread B will pause further execution until the function targeted by thread A releases the lock again.
- Thus, a locked lock only ever pauses execution of a thread, if its targeted function wants (and waits) to acquire the very same lock itself. Thus, by thread A acquiring the lock, it can only prevent thread B from acquiring the same lock, nothing more, nothing less.
If I want to use a lock to prevent race conditions when setting a variable, I (as the programmer) need to:
- pass a lock to all functions targeted by threads that will want to set the variable and
- acquire the lock in every function and every time before I set the variable (and release it afterwards). (*)
- If I create even only one thread targeting a function without providing it a reference to the lock object and let it set the variable or
- if I set the variable via a thread whose targeted function has the lock object, but doesn't acquire it prior to the operation, I will have failed to implement thread-safe setting of the variable.
(*) The lock should be acquired as long as the variable must not be accessed by other threads. Right now, I like to compare that to a database transaction... I lock the database (~ acquire a lock) until my set of instructions is completed, then I commit (~ release the lock).
Example If I wanted to create a class whose member _value
should be set in a thread-safe fashion, I would implement one of these two versions:
class Version1:
def __init__(self):
self._value:int = 0
self._lock:threading.Lock = threading.Lock()
def getValue(self) -> int:
"""Getting won't be protected in this example."""
return self._value
def setValue(self, val:int) -> None:
"""This will be made thread-safe by member lock."""
with self._lock:
self._value = val
v1 = Version1()
t1_1 = threading.Thread(target=v1.setValue, args=(1)).start()
t1_2 = threading.Thread(target=v1.setValue, args=(2)).start()
class Version2:
def __init__(self):
self._value:int = 0
def getValue(self) -> int:
"""Getting won't be protected in this example."""
return self._value
def setValue(self, val:int, lock:threading.Lock) -> None:
"""This will be made thread-safe by injected lock."""
with self._lock:
self._value = val
v2 = Version2()
l = threading.Lock()
t2_1 = threading.Thread(target=v2.setValue, args=(1, l)).start()
t2_2 = threading.Thread(target=v2.setValue, args=(2, l)).start()
- In
Version1
, I, as the class provider, can guarantee that setting_value
is always thread-safe... - ...because in
Version2
, the user of my class might pass to different lock objects to the two spawned threads and thus render the lock protection useless. - If I want to give the user of my class the freedom to include the setting of
_value
into a larger collection of steps that should be executed in a thread-safe manner, I could inject aLock
reference intoVersion1
's__init__
function and assign that to the_lock
member. Thus, the thread-safe operation of the class would be guaranteed while still allowing the user of the class to use "her own" lock for that purpose.
A score from 0-15 will now rate how well I have (mis)understood locks... :-D
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)