Go/Python异步桥接

huangapple go评论119阅读模式
英文:

Go/Python asynchronous bridge

问题

我写了一个客户端来处理低级别的TLS连接参数,比如ClientHello等。

我使用Go语言来完成这个任务,因为在Go中更容易实现。我的主程序(网页爬虫)是用Python编写的。我通过ctypes将Go源代码连接到我的Python文件中的DLL。到目前为止,我的网页爬虫结构是异步的,可以同时处理多个连接。

不幸的是,我的Go客户端不是异步的。有没有办法在Python中对它进行更改,使其异步等待ctypes指针的响应,直到响应到达为止?目前它正在等待响应,但同时阻塞了所有其他代码的执行。

编辑:
下面是代码示例:

  1. async def request(self, method, url, headers, body=None, rawBody=None, pseudoHeaderOrder=["method", "authority", "scheme", "path"]):
  2. global httpLib
  3. global initFunc
  4. global requestFunc
  5. global changeProxyFunc
  6. global freePointerFunc
  7. config = {
  8. "id": self.cid,
  9. "method": method.upper(),
  10. "timeout": 20000,
  11. "url": url,
  12. "pseudoHeaderOrder": pseudoHeaderOrder,
  13. "headers": headers
  14. }
  15. #Critical
  16. if body:
  17. config["body"] = body
  18. if rawBody:
  19. rawBody = [b for b in bytes(rawBody, "utf-8")]
  20. config["rawBody"] = rawBody
  21. config = json.dumps(config)
  22. #print(config)
  23. #THIS PART CASTS THE REQUEST
  24. ptr = requestFunc(config.encode('utf-8'))
  25. string = ctypes.cast(ptr, ctypes.c_char_p).value.decode("utf-8")
  26. #THIS PART CLEARS THE POINTER
  27. freePointerFunc(ptr)
  28. #...
英文:

I wrote a client to handle lower-level TLS connection parameters like ClientHellos etc.

I did this in Go since it's a lot easier there. My main program (webscraper) is in Python. I connected the Go source to my Python file through a DLL via ctypes. My webscraper structure was asynchronous so far, to handle multiple connections at a time.

Unfortunately, my Go client is not asynchronous. Is there a way I can change it in Python so it asynchronously awaits a response from the ctypes pointer until it is there? Right now it's waiting for a response but blocks all other code executions in the meantime obviously.

EDIT:
Code example below

  1. async def request(self, method, url, headers, body=None, rawBody=None, pseudoHeaderOrder=["method", "authority", "scheme", "path"]):
  2. global httpLib
  3. global initFunc
  4. global requestFunc
  5. global changeProxyFunc
  6. global freePointerFunc
  7. config = {
  8. "id": self.cid,
  9. "method": method.upper(),
  10. "timeout": 20000,
  11. "url": url,
  12. "pseudoHeaderOrder": pseudoHeaderOrder,
  13. "headers": headers
  14. }
  15. #Critical
  16. if body:
  17. config["body"] = body
  18. if rawBody:
  19. rawBody = [b for b in bytes(rawBody, "utf-8")]
  20. config["rawBody"] = rawBody
  21. config = json.dumps(config)
  22. #print(config)
  23. #THIS PART CASTS THE REQUEST
  24. ptr = requestFunc(config.encode('utf-8'))
  25. string = ctypes.cast(ptr, ctypes.c_char_p).value.decode("utf-8")
  26. #THIS PART CLEARS THE POINTER
  27. freePointerFunc(ptr)
  28. #...

答案1

得分: 1

你可以使用执行器(executor)将阻塞调用移动到单独的线程或进程中。

类似这样的代码应该可以工作:

  1. async def request(self, method, url, headers, body=None, rawBody=None, pseudoHeaderOrder=["method", "authority", "scheme", "path"]):
  2. global httpLib
  3. global initFunc
  4. global requestFunc
  5. global changeProxyFunc
  6. global freePointerFunc
  7. config = {
  8. "id": self.cid,
  9. "method": method.upper(),
  10. "timeout": 20000,
  11. "url": url,
  12. "pseudoHeaderOrder": pseudoHeaderOrder,
  13. "headers": headers
  14. }
  15. #关键部分
  16. if body:
  17. config["body"] = body
  18. if rawBody:
  19. rawBody = [b for b in bytes(rawBody, "utf-8")]
  20. config["rawBody"] = rawBody
  21. config = json.dumps(config)
  22. # 将阻塞代码移动到单独的函数中
  23. def blocking_io():
  24. ptr = requestFunc(config.encode('utf-8'))
  25. string = ctypes.cast(ptr, ctypes.c_char_p).value.decode("utf-8")
  26. freePointerFunc(ptr)
  27. return string
  28. # 异步等待结果
  29. loop = asyncio.get_running_loop()
  30. string = await loop.run_in_executor(None, blocking_io)
  31. #...

你可以参考这里了解更多关于执行代码在线程或进程池中的信息。

英文:

You can move the blocking call to a separate thread/process using an executor.

Something like this should work,

  1. async def request(self, method, url, headers, body=None, rawBody=None, pseudoHeaderOrder=["method", "authority", "scheme", "path"]):
  2. global httpLib
  3. global initFunc
  4. global requestFunc
  5. global changeProxyFunc
  6. global freePointerFunc
  7. config = {
  8. "id": self.cid,
  9. "method": method.upper(),
  10. "timeout": 20000,
  11. "url": url,
  12. "pseudoHeaderOrder": pseudoHeaderOrder,
  13. "headers": headers
  14. }
  15. #Critical
  16. if body:
  17. config["body"] = body
  18. if rawBody:
  19. rawBody = [b for b in bytes(rawBody, "utf-8")]
  20. config["rawBody"] = rawBody
  21. config = json.dumps(config)
  22. # Move blocking code to separate function
  23. def blocking_io():
  24. ptr = requestFunc(config.encode('utf-8'))
  25. string = ctypes.cast(ptr, ctypes.c_char_p).value.decode("utf-8")
  26. freePointerFunc(ptr)
  27. return string
  28. # Aschronously wait on the result
  29. loop = asyncio.get_running_loop()
  30. string = await loop.run_in_executor(None, blocking_io)
  31. #...

huangapple
  • 本文由 发表于 2021年8月21日 18:06:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/68872029.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定