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

lokaqttq  于 2021-09-13  发布在  Java
关注(0)|答案(1)|浏览(346)

我一直在试图弄清楚上下文管理器越来越多,我越喜欢它,我似乎发现更多的问题。我目前的问题是,我目前没有锁,这可能导致两个或更多线程可能最终拥有相同的共享值,因为我只希望使用一个值。

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键:值设置为available,如果它可用,那么我们将它设置为busy->do some stuff,然后退出它(通过设置将相同的值释放为available)-然而,我的问题是,在极少数情况下,似乎有两个以上的线程能够获得相同的值我想阻止的是同一个代理,我希望当时只有一个线程能够访问上下文管理器,这样我们就可以将代理值设置为busy,这样其他线程就不能使用它了。
如何锁定,以便只有一个线程可以将代理设置为忙碌,从而避免两个或多个线程在同一个代理上设置为忙碌?

r1zhe5dt

r1zhe5dt1#

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

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
---

相关问题