をこれがあります。
これは、一定時間以上コントロールを盗む機能があれば、discordのクライアントが無効な状態になることを意味します(おそらく、クライアントの次のメソッド呼び出し時に例外が現れます)。
discordモジュールクライアントがdiscordサーバーにpingできるようにするには、真のマルチスレッドソリューションを使用する必要があります。
重大な処理を別のプロセスにオフロードすることです(Pythonにはグローバルインタプリタロックがあるため、別のスレッドは実行しません)。そして、この不和ボットを作業キューに入れる責任がある薄いレイヤーとして使用します。
関連読書: https://discordpy.readthedocs.io/en/latest/faq.html#what-does-blocking-mean
例ソリューション...これは問題の範囲を超えての方法ですが、私はすでにほとんどが書かれたコードを持っていました。
これは不和リスナーである:私はより多くの時間を持っていた場合、私は短いソリューション:)
2部、不和の相互作用および処理サーバを記述します。
import discord
import re
import asyncio
import traceback
import websockets
import json
# Call a function on other server
async def call(methodName, *args, **kwargs):
async with websockets.connect('ws://localhost:9001/meow') as websocket:
payload = json.dumps({"method":methodName, "args":args, "kwargs": kwargs})
await websocket.send(payload)
#...
resp = await websocket.recv()
#...
return resp
client = discord.Client()
tok = open("token.dat").read()
@client.event
async def on_ready():
print('Logged in as')
print(client.user.name)
print(client.user.id)
print('------')
@client.event
async def on_error(event, *args, **kwargs):
print("Error?")
@client.event
async def on_message(message):
try:
if message.author.id == client.user.id:
return
m = re.match("(\w+) for (\d+).*?", message.content)
if m:
g = m.groups(1)
methodName = g[0]
someNumber = int(g[1])
response = await call(methodName, someNumber)
if response:
await client.send_message(message.channel, response[0:2000])
except Exception as e:
print (e)
print (traceback.format_exc())
client.run(tok)
これは、重い要求を処理するためのワーカーサーバーです。この部分を同期または非同期にすることができます。
1つのpythonプロセスから別のプロセスにデータを送るために、websocketと呼ばれる魔法を使うことにしました。しかし、あなたはあなたが望むものを使うことができます。あるスクリプトがファイルをディレクトリに書き込むようにすることができ、他のスクリプトはファイルを読み込んで処理することができます。今
import tornado
import tornado.websocket
import tornado.httpserver
import json
import asyncio
import inspect
import time
class Handler:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def consume(self, text):
return "You said {0} and I say hiya".format(text)
async def sweeps(self, len):
await asyncio.sleep(len)
return "Slept for {0} seconds asynchronously!".format(len)
def sleeps(self, len):
time.sleep(len)
return "Slept for {0} seconds synchronously!".format(len)
class MyService(Handler, tornado.websocket.WebSocketHandler):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def stop(self):
Handler.server.stop()
def open(self):
print("WebSocket opened")
def on_message(self, message):
print (message)
j = json.loads(message)
methodName = j["method"]
args = j.get("args",())
method = getattr(self, methodName)
if inspect.iscoroutinefunction(method):
loop = asyncio.get_event_loop()
task = loop.create_task(method(*args))
task.add_done_callback(lambda res: self.write_message(res.result()))
future = asyncio.ensure_future(task)
elif method:
resp = method(*args)
self.write_message(resp)
def on_close(self):
print("WebSocket closed")
application = tornado.web.Application([
(r'/meow', MyService),
])
if __name__ == "__main__":
from tornado.platform.asyncio import AsyncIOMainLoop
AsyncIOMainLoop().install()
http_server = tornado.httpserver.HTTPServer(application)
Handler.server = http_server
http_server.listen(9001)
asyncio.get_event_loop().run_forever()
あなたは別のPythonスクリプトで両方のプロセスを実行して、あなたのボット「100のための睡眠」を伝える場合、それは喜んで100秒間スリープします! asyncio stuffはmake-shift作業キューとして機能し、別々のpythonスクリプトとして実行することで、リスナーをバックエンド処理から適切に分離することができます。
ここで、あなたの機能が「サーバー」の部分でどれくらい実行されても、クライアントのパーツはディスパードサーバーにpingを実行することは決してありません。
画像がとにかくアップロードに失敗した、しかし...、これは睡眠が同期していることに注意してください...寝て返信するボットに伝える方法です。 http://i.imgur.com/N4ZPPbB.png
不和の仕組みについて、この洞察をいただきありがとうございます。残念ながら、私はスレッド型プログラミングと非同期プログラミングの専門家ではありません。この「薄い層」が何であるか、そしてそれをどう実装するかをもう少し説明できますか? – shrx
は多くの方法がありますが、その議論は芋この質問の範囲を超えています。私は私の個人的なコードをブラウズします(それはかなり悪い...私はotを書いたので)、私はあなたのためにいくつかのスニペットとアイデアを抽出できるかどうかを見てください:) – JamEnergy
例を徹底的に説明していただきありがとうございます。 – shrx