如何使用上下文管理器锁定



我越来越多地试图弄清楚上下文管理器,我越投入其中,似乎发现的问题就越多。我目前的问题是,我目前没有锁,这可能导致两个或多个线程最终可能具有相同的共享值,因为我只希望使用一个值。

import random
import threading
import time
list_op_proxy = [
"https://123.123.12.21:12345",
"http://123.123.12.21:54321",
]
proxy_dict = dict(zip(list_op_proxy, ['available'] * len(list_op_proxy)))
proxy_dict['http://123.123.12.21:987532'] = "busy"

class AvailableProxies:
def __enter__(self):
while True:
available = [att for att, value in proxy_dict.items() if "available" in value]
if available:
self.proxy = random.choice(available)
proxy_dict[self.proxy] = "busy"
return self.proxy
else:
continue
def __exit__(self, exc_type, exc_val, exc_tb):
proxy_dict[self.proxy] = "available"

def handler(name):
with AvailableProxies() as proxy:
print(f"{name} | Proxy in use: {proxy}")
# Adding 2 seconds as we want to see if it actually wait for the availability
time.sleep(2)

for i in range(5):
threading.Thread(target=handler, args=(f'Thread {i}',)).start()

正如你在我的上下文管理器中看到的,我想随机循环一个dict-key:value,它的值设置为可用,如果它可用,那么我们将其设置为忙->做一些事情,然后退出它(通过将相同的值设置为可用来释放(-然而,我的问题是,在极少数情况下,似乎有两个以上的线程能够获得我想要阻止的同一个代理,我希望一次只有一个线程能够访问上下文管理器,这样我们就可以将代理值设置为繁忙,这样其他线程就无法使用它。

我如何锁定,以便只有一个线程可以将代理设置为繁忙,这样就不会发生两个或多个线程在同一代理上设置为繁忙的情况?

您只需要在寻找代理时锁定,并在找到代理后释放锁定(用法与您之前的问题相同,无论您是否使用上下文管理器(,我只是添加了更多调试消息:

import random
import threading
import time
list_op_proxy = [
"https://123.123.12.21:12345",
"http://123.123.12.21:54321",
]
proxy_dict = dict(zip(list_op_proxy, ['available'] * len(list_op_proxy)))
proxy_dict['http://123.123.12.21:987532'] = "busy"
proxy_lock = threading.Lock()

class AvailableProxies:
def __enter__(self):
proxy_lock.acquire()
self.proxy = None
while not self.proxy:
available = [
att for att, value in proxy_dict.items() if "available" in value
]
if available:
print('%d proxies available' % len(available))
self.proxy = random.choice(available)
proxy_dict[self.proxy] = "busy"
break
else:
print("Waiting ... not proxy available")
time.sleep(.2)
continue
proxy_lock.release()
return self.proxy
def __exit__(self, exc_type, exc_val, exc_tb):
proxy_dict[self.proxy] = "available"

def handler(name):
with AvailableProxies() as proxy:
print(f"{name} | Proxy in use: {proxy}")
# Adding 2 seconds as we want to see if it actually wait for the availability
time.sleep(.1)

for j in range(5):
threads = [threading.Thread(target=handler, args=(i, )) for i in range(3)]
[t.start() for t in threads]
[t.join() for t in threads]
print("---")

输出:

2 proxies available
0 | Proxy in use: http://123.123.12.21:54321
1 proxies available
1 | Proxy in use: https://123.123.12.21:12345
Waiting ... not proxy available
2 proxies available
2 | Proxy in use: https://123.123.12.21:12345
---
2 proxies available
0 | Proxy in use: http://123.123.12.21:54321
1 proxies available
1 | Proxy in use: https://123.123.12.21:12345
Waiting ... not proxy available
2 proxies available
2 | Proxy in use: http://123.123.12.21:54321
---
2 proxies available
0 | Proxy in use: https://123.123.12.21:12345
1 proxies available
1 | Proxy in use: http://123.123.12.21:54321
Waiting ... not proxy available
2 proxies available
2 | Proxy in use: https://123.123.12.21:12345
---
2 proxies available
0 | Proxy in use: https://123.123.12.21:12345
1 proxies available
1 | Proxy in use: http://123.123.12.21:54321
Waiting ... not proxy available
2 proxies available
2 | Proxy in use: https://123.123.12.21:12345
---
2 proxies available
0 | Proxy in use: http://123.123.12.21:54321
1 proxies available
1 | Proxy in use: https://123.123.12.21:12345
Waiting ... not proxy available
2 proxies available
2 | Proxy in use: http://123.123.12.21:54321
---