Race Condition in Python.

A race condition happens when two or more threads or processes try to access and modify the same shared resource at the same time, and the program’s behavior depends on the timing of their execution.

Key Points:

  1. Cause: Occurs due to a lack of proper synchronization.
  2. Effect: Leads to unpredictable or incorrect outcomes because the threads “race” to complete their operations first.
  3. Example:

    • Two threads try to update a shared counter:
    <span>counter</span> <span>=</span> <span>0</span>
    <span>def</span> <span>increment</span><span>():</span>
    <span>global</span> <span>counter</span>
    <span>for</span> <span>_</span> <span>in</span> <span>range</span><span>(</span><span>1000</span><span>):</span>
    <span>counter</span> <span>+=</span> <span>1</span> <span># This is not thread-safe </span>
    <span>thread1</span> <span>=</span> <span>threading</span><span>.</span><span>Thread</span><span>(</span><span>target</span><span>=</span><span>increment</span><span>)</span>
    <span>thread2</span> <span>=</span> <span>threading</span><span>.</span><span>Thread</span><span>(</span><span>target</span><span>=</span><span>increment</span><span>)</span>
    <span>thread1</span><span>.</span><span>start</span><span>()</span>
    <span>thread2</span><span>.</span><span>start</span><span>()</span>
    <span>thread1</span><span>.</span><span>join</span><span>()</span>
    <span>thread2</span><span>.</span><span>join</span><span>()</span>
    <span>print</span><span>(</span><span>counter</span><span>)</span> <span># Output may vary and be less than 2000 </span>
     <span>counter</span> <span>=</span> <span>0</span>
    
     <span>def</span> <span>increment</span><span>():</span>
         <span>global</span> <span>counter</span>
         <span>for</span> <span>_</span> <span>in</span> <span>range</span><span>(</span><span>1000</span><span>):</span>
             <span>counter</span> <span>+=</span> <span>1</span>  <span># This is not thread-safe </span>
     <span>thread1</span> <span>=</span> <span>threading</span><span>.</span><span>Thread</span><span>(</span><span>target</span><span>=</span><span>increment</span><span>)</span>
     <span>thread2</span> <span>=</span> <span>threading</span><span>.</span><span>Thread</span><span>(</span><span>target</span><span>=</span><span>increment</span><span>)</span>
    
     <span>thread1</span><span>.</span><span>start</span><span>()</span>
     <span>thread2</span><span>.</span><span>start</span><span>()</span>
     <span>thread1</span><span>.</span><span>join</span><span>()</span>
     <span>thread2</span><span>.</span><span>join</span><span>()</span>
    
     <span>print</span><span>(</span><span>counter</span><span>)</span>  <span># Output may vary and be less than 2000 </span>
    counter = 0 def increment(): global counter for _ in range(1000): counter += 1 # This is not thread-safe thread1 = threading.Thread(target=increment) thread2 = threading.Thread(target=increment) thread1.start() thread2.start() thread1.join() thread2.join() print(counter) # Output may vary and be less than 2000
  • Without proper synchronization, the result is unpredictable because threads interfere with each other.

How to Prevent:

  • Use locks (e.g., Lock or RLock) to ensure only one thread accesses the critical section at a time.
  • Example with a lock:
<span>import</span> <span>threading</span>
<span>counter</span> <span>=</span> <span>0</span>
<span>lock</span> <span>=</span> <span>threading</span><span>.</span><span>Lock</span><span>()</span>
<span>def</span> <span>increment</span><span>():</span>
<span>global</span> <span>counter</span>
<span>for</span> <span>_</span> <span>in</span> <span>range</span><span>(</span><span>1000</span><span>):</span>
<span>with</span> <span>lock</span><span>:</span> <span># Ensures only one thread accesses this block at a time </span> <span>counter</span> <span>+=</span> <span>1</span>
<span>thread1</span> <span>=</span> <span>threading</span><span>.</span><span>Thread</span><span>(</span><span>target</span><span>=</span><span>increment</span><span>)</span>
<span>thread2</span> <span>=</span> <span>threading</span><span>.</span><span>Thread</span><span>(</span><span>target</span><span>=</span><span>increment</span><span>)</span>
<span>thread1</span><span>.</span><span>start</span><span>()</span>
<span>thread2</span><span>.</span><span>start</span><span>()</span>
<span>thread1</span><span>.</span><span>join</span><span>()</span>
<span>thread2</span><span>.</span><span>join</span><span>()</span>
<span>print</span><span>(</span><span>counter</span><span>)</span> <span># Output will always be 2000 </span>
  <span>import</span> <span>threading</span>

  <span>counter</span> <span>=</span> <span>0</span>
  <span>lock</span> <span>=</span> <span>threading</span><span>.</span><span>Lock</span><span>()</span>

  <span>def</span> <span>increment</span><span>():</span>
      <span>global</span> <span>counter</span>
      <span>for</span> <span>_</span> <span>in</span> <span>range</span><span>(</span><span>1000</span><span>):</span>
          <span>with</span> <span>lock</span><span>:</span>  <span># Ensures only one thread accesses this block at a time </span>              <span>counter</span> <span>+=</span> <span>1</span>

  <span>thread1</span> <span>=</span> <span>threading</span><span>.</span><span>Thread</span><span>(</span><span>target</span><span>=</span><span>increment</span><span>)</span>
  <span>thread2</span> <span>=</span> <span>threading</span><span>.</span><span>Thread</span><span>(</span><span>target</span><span>=</span><span>increment</span><span>)</span>

  <span>thread1</span><span>.</span><span>start</span><span>()</span>
  <span>thread2</span><span>.</span><span>start</span><span>()</span>
  <span>thread1</span><span>.</span><span>join</span><span>()</span>
  <span>thread2</span><span>.</span><span>join</span><span>()</span>

  <span>print</span><span>(</span><span>counter</span><span>)</span>  <span># Output will always be 2000 </span>
import threading counter = 0 lock = threading.Lock() def increment(): global counter for _ in range(1000): with lock: # Ensures only one thread accesses this block at a time counter += 1 thread1 = threading.Thread(target=increment) thread2 = threading.Thread(target=increment) thread1.start() thread2.start() thread1.join() thread2.join() print(counter) # Output will always be 2000

Enter fullscreen mode Exit fullscreen mode

Interview Tips:

  • Tt’s caused by unsynchronized access to shared resources.
  • Always mention locks or synchronization to prevent it.

原文链接:Race Condition in Python.

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
Your dream is like a flower. if you water it patiently, the flower will come out beautifully.
即使是最简单的梦想,用心浇灌,也能开出绚烂的花
评论 抢沙发

请登录后发表评论

    暂无评论内容