Я использую Tornado Server, 4.4.2 и pypy 5.9.0 и python 2.7.13, размещенные на Ubuntu 16.04.3 LTS.
Новый клиент входит в систему, создается новый класс и передается сокет, поэтому диалог можно поддерживать. Я использую глобальный список клиентов[] для хранения классов. начальный диалог выглядит так:
clients = []
class RegisterWebSocket(SockJSConnection):
# intialize the class and handle on-open (some things left out)
def on_open(self,info):
self.ipaddress = info.headers['X-Real-Ip']
def on_message(self, data):
coinlist = []
msg = json.loads(data)
if 'coinlist' in msg:
coinlist = msg['coinlist']
if 'currency' in msg:
currency = msg['currency']
tz = pendulum.timezone('America/New_York')
started = pendulum.now(tz).to_day_datetime_string()
ws = WebClientUpdater(self, self.clientid, coinlist,currency,
started, self.ipaddress)
clients.append(ws)
Класс ws показан ниже, и я использую периодический обратный вызов tornado для обновления клиентов с их конкретной информацией каждые 20 секунд.
class WebClientUpdater(SockJSConnection):
def __init__(self, ws,id, clist, currency, started, ipaddress):
super(WebClientUpdater,self).__init__(ws.session)
self.ws = ws
self.id = id
self.coinlist = clist
self.currency = currency
self.started = started
self.ipaddress = ipaddress
self.location = loc
self.loop = tornado.ioloop.PeriodicCallback(self.updateCoinList,
20000, io_loop=tornado.ioloop.IOLoop.instance())
self.loop.start()
self.send_msg('welcome '+ id)
def updateCoinList(self):
pdata = db.getPricesOfCoinsInCurrency(self.coinlist,self.currency)
self.send(dict(priceforcoins = pdata))
def send_msg(self,msg):
self.send(msg)
Я также начинаю с 60-секундного периодического обратного вызова при запуске, чтобы контролировать клиентов на наличие закрытых соединений и удалять их из списка client[]. Который я поместил в строку запуска, чтобы вызвать внутренне определение, например
if __name__ == "__main__":
app = make_app()
app.listen(options.port)
ScheduleSocketCleaning()
а также
def ScheduleSocketCleaning():
def cleanSocketHouse():
print "checking sockets"
for x in clients:
if x.is_closed:
x = None
clients[:] = [y for y in clients if not y.is_closed ]
loop = tornado.ioloop.PeriodicCallback(cleanSocketHouse, 60000,
io_loop=tornado.ioloop.IOLoop.instance())
loop.start()
Если я наблюдаю за сервером с помощью TOP, я вижу, что он использует 4% типичного процессора с пиками до 60+ сразу, но позже, скажем, через несколько часов, он становится на уровне 90% и остается там.
Я использовал strace и вижу огромное количество вызовов Stat для одних и тех же файлов с ошибками, показанными в представлении strace -c, но я не могу найти никаких ошибок в текстовом файле, используя -o trace.log. Как я могу найти эти ошибки?
Но я также заметил, что большую часть времени занимает epoll_wait.
%время
- 41,61 0,068097 7 9484 epoll_wait
- 26,65 0,043617 0 906154 2410 стат
- 15,77 0,025811 0 524072 чтение
- 10,90 0,017840 129 138 брк
- 2,41 0,003937 9 417 Мэдвайз
- 2,04 0,003340 0 524072 лсик
- 0,56 0,000923 3 298 отправить
- 0,06 0,000098 0 23779
- 100,00 0,163663 1989527 2410 всего
Обратите внимание на ошибки 2410 выше.
Когда я просматриваю выходной поток strace, используя прикрепленный pid, я просто вижу бесконечные вызовы Stat для одних и тех же файлов.
Может ли кто-нибудь посоветовать мне, как лучше отладить эту ситуацию? Имея всего два клиента и 20 секунд между обновлениями клиентов, я ожидаю, что загрузка ЦП (на этом этапе прототипа нет других пользователей сайта) будет менее 1% или около того.
epoll_wait
, потому что именно там происходит планирование. - person freakish   schedule 18.12.2017