我有一个简单的类,用于获取URL,同时使用单独线程上的新循环定期更新访问令牌:
import asyncio
import aiohttp
from threading import Thread
from random import randint
LOOP = asyncio.get_event_loop()
NEW_LOOP = asyncio.new_event_loop()
t = Thread(target=NEW_LOOP.run_forever)
t.start()
class SOME_CLASS(object):
def __init__(self, loop=LOOP, new_loop=NEW_LOOP):
self.token = None
self.loop = loop
self.new_loop = new_loop
self.semaphore = asyncio.Semaphore(3)
self.session = aiohttp.ClientSession(loop=self.loop)
asyncio.run_coroutine_threadsafe(self.get_token(), self.new_loop)
def _get_headers(self):
headers = {
'x-access-token': str(self.token),
'content-type': 'application/json',
}
return headers
async def get_token(self):
while True:
self.token = randint(1, 100)
await asyncio.sleep(2)
async def fetch(self, url):
async with self.semaphore:
headers = self._get_headers()
async with self.session.get(url, headers=headers) as response:
await response.read()
return headers
async def fetch_all(self):
urls = ['https://httpbin.org/get?x={i}'for i in range(1000)]
futures = asyncio.as_completed([self.fetch(url) for url in urls])
for future in futures:
await asyncio.sleep(1)
headers = await future
print(f'headers: {headers} token: {self.token}')
def run(self):
self.loop.run_until_complete(self.fetch_all())
if __name__ == '__main__':
sc = SOME_CLASS()
sc.run()然而,我注意到,即使self.token确实每两秒更新一次,存储在headers中的令牌仍然保持不变。看起来好像self._get_headers()是提前被调用的,而不是在它获得信号量之后:
headers: {'x-access-token': '8', 'content-type': 'application/json'} token: 8
headers: {'x-access-token': '8', 'content-type': 'application/json'} token: 8
headers: {'x-access-token': '8', 'content-type': 'application/json'} token: 78
headers: {'x-access-token': '8', 'content-type': 'application/json'} token: 78
headers: {'x-access-token': '8', 'content-type': 'application/json'} token: 41
headers: {'x-access-token': '8', 'content-type': 'application/json'} token: 56
headers: {'x-access-token': '8', 'content-type': 'application/json'} token: 56
headers: {'x-access-token': '8', 'content-type': 'application/json'} token: 74
headers: {'x-access-token': '8', 'content-type': 'application/json'} token: 74
headers: {'x-access-token': '8', 'content-type': 'application/json'} token: 4
headers: {'x-access-token': '8', 'content-type': 'application/json'} token: 4
headers: {'x-access-token': '8', 'content-type': 'application/json'} token: 10
headers: {'x-access-token': '8', 'content-type': 'application/json'} token: 10
headers: {'x-access-token': '8', 'content-type': 'application/json'} token: 44
headers: {'x-access-token': '8', 'content-type': 'application/json'} token: 44
headers: {'x-access-token': '8', 'content-type': 'application/json'} token: 28
headers: {'x-access-token': '8', 'content-type': 'application/json'} token: 28如何确保在发送http请求之前,令牌在headers中得到实际更新?
发布于 2018-05-27 09:32:11
asyncio.sleep(2)设置得很高,将其设置为0.2,将您的调试打印放入fetch并查看其更新
发布于 2018-05-27 10:10:51
对于一个基本的Python问题,您有一个复杂的包装器。变量self.token是一个简单的整数。存储在headers字典中的值是这个简单整数的字符串表示。当您将self.token重新赋值给一个不同的整数时,程序将无法知道您希望同时更改哪些其他对象。
一种解决方案是使self.token成为具有内部状态的对象。该对象可以在程序中的不同位置引用。当你改变它的内部状态时,它当然会立即生效。下面是一个带有class Token的小程序来说明这一点。我希望你能让它适应你更复杂的情况。我不认为协程的使用会影响这一点。我认为如果您将x-access-token的值赋给self.token,它现在是Token的一个实例,那么您就完成了解决方案的大部分工作。
import random
# This way doesn't work
class MyClass:
def __init__(self):
self.token = random.randint(1, 100)
def change_token(self):
self.token = random.randint(1, 100)
c = MyClass()
a = c.token
for _ in range(10):
c.change_token()
print(a, c.token) # a does not change when c.token does
# This works
class Token:
def __init__(self, n):
self.token = n
def __repr__(self):
return str(self.token)
def set_token(self, n):
self.token = n
class MyClass2:
def __init__(self):
self.token = Token(random.randint(1, 100))
def change_token(self):
self.token.set_token(random.randint(1, 100))
print()
c = MyClass2()
a = c.token
for _ in range(10):
c.change_token()
print(a, c.token) # a and c.token are the same objecthttps://stackoverflow.com/questions/50548263
复制相似问题