ThreadPoolExecutor 饥饿

ThreadPoolExcutor starvation

我正在尝试 运行 2 个不同的阻塞函数,它们使用相同的全局变量 a

代码:

from concurrent.futures import ThreadPoolExecutor, as_completed
import threading
import keyboard

a = 0
def incA():
    global a
    
    while True:
        print(f'inc a: {a} -> {a+1}', end = '\n')
        a+=1
        if keyboard.is_pressed('q'):  # if key 'q' is pressed 
            break
        
def printA():
    # a is read-only
    
    while True:
        print(f'print a: {a}', end = '\n')
        if keyboard.is_pressed('q'):  # if key 'q' is pressed 
            break

with ThreadPoolExecutor(max_workers=2) as executor:
    f1 = executor.submit(incA)
    f2 = executor.submit(printA)

期望的输出:

.
.
.
inc a: 15640 -> 15641
print a: 15641
inc a: 15641 -> 15642
print a: 15642
inc a: 15642 -> 15643
print a: 15643
.
.
.

此代码的给定输出是这样的:

print a: 1428inc a: 1429 -> 1430

print a: 1429
inc a: 1430 -> 1431print a: 1430

inc a: 1431 -> 1432print a: 1431

inc a: 1432 -> 1433print a: 1432

inc a: 1433 -> 1434print a: 1433

inc a: 1434 -> 1435print a: 1434

inc a: 1435 -> 1436print a: 1435

inc a: 1436 -> 1437print a: 1436

这接近我想要的,但是如您所见,即使我明确地把 end='\n' 在函数中。


我尝试给系统加锁,结果导致饿死。在每个函数的 while True 循环中,我添加了这些行:

def printA():
    global lock 
    # a is read-only
    
    while True:
        try:
            lock.acquire()
            print(f'print a: {a}', end = '\n')
            if keyboard.is_pressed('q'):  # if key 'q' is pressed 
                break
        finally:
            lock.release()

导致此输出(饥饿):

inc a: 1319 -> 1320
inc a: 1320 -> 1321
inc a: 1321 -> 1322
inc a: 1322 -> 1323
inc a: 1323 -> 1324
inc a: 1324 -> 1325
print a: 1325
print a: 1325
print a: 1325
print a: 1325
print a: 1325
print a: 1325

使用 Ron Serruya 的回答建议 link 我们在消息中添加换行符以防止分离。

修改代码

from concurrent.futures import ThreadPoolExecutor, as_completed
import threading
import keyboard

a = 0
def incA():
    global a
    
    while True:
        print(f'inc a: {a} -> {a+1}\n', end = '')  # Place newline in message to prevent separation
        a+=1
        if keyboard.is_pressed('q'):  # if key 'q' is pressed 
            break
        
def printA():
    # a is read-only
    
    while True:
        print(f'print a: {a}\n', end = '') # Place newline in message to prevent separation
        if keyboard.is_pressed('q'):  # if key 'q' is pressed 
            break

with ThreadPoolExecutor(max_workers=2) as executor:
    f1 = executor.submit(incA)
    f2 = executor.submit(printA)

输出

...
inc a: 3459 -> 3460
print a: 3459
print a: 3459
inc a: 3460 -> 3461
print a: 3460
inc a: 3461 -> 3462
print a: 3461
inc a: 3462 -> 3463
inc a: 3463 -> 3464
print a: 3463
inc a: 3464 -> 3465
print a: 3464
inc a: 3465 -> 3466
print a: 3465
inc a: 3466 -> 3467
print a: 3466
...