首页 > 解决方案 > 如何使用上下文管理器锁定

问题描述

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

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

正如您在我的上下文管理器中看到的那样,我想随机循环一个字典键:值,它的值设置为可用,如果它可用,那么我们将它设置为忙-> 做一些事情然后退出它(通过设置释放相同的值可用) - 但是我的问题是,在极少数情况下,似乎超过 2 个线程能够获得我想要阻止的相同代理,我希望只有一个线程能够访问上下文管理器时间,所以我们可以将代理值设置为忙,这样其他线程就不能接受它。

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

标签: pythonpython-3.xmultithreading

解决方案


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

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

推荐阅读