Почему мой код хорошо работает в windows, но не в ubuntu

Этот код хорошо работает в Windows, но когда я перемещаю его на свой vps (ubuntu16.04, python3.6), возникает некоторая проблема.

import json
import time
import threading
import websocket
import requests
from datetime import datetime, timedelta, timezone

def run_in_thread(sec):
    def _wrapper(func):
        def __wrapper(self, *args, **kwargs):
            timer = threading.Timer(sec, func, [self, *args])
            timer.start()
            self._ws.on_open = self.on_open
            self._ws.run_forever()
            return self._result
        return __wrapper
    return _wrapper

class CybexHistoryAPI(object):
    def __init__(self, ws_endp):
        self._endpoint = ws_endp
        self.reset()

    def reset(self):
        self._ws = websocket.WebSocketApp(self._endpoint,
            on_message = self.on_message,
            on_error = self.on_error,
            on_close = self.on_close)
        self._login_api_id = -1
        self._history_api_id = -1
        self._api_is_ready = False
        self._call_id = 1

    def _send_msg(self, params):
        call = {"id": self._call_id, "method": "call",
                "params": params}
        self._ws.send(json.dumps(call))
        self._call_id += 1

    def on_open(self, ws):
        self._send_msg([1, "login", ["",""]])
        self._call_id = 1

    def on_error(self, ws, error):
        print('Remote node send an error [{}]'.format(error))

    def on_close(self, ws):
        print('Remote node closed our connection')

    def on_message(self, ws, msg):
        print(msg)
        if self._login_api_id < 0:
            result = json.loads(msg)
            self._login_api_id = result['id']
            self._send_msg([self._login_api_id, "history", []])
        elif self._history_api_id < 0:
            result = json.loads(msg)
            self._history_api_id = result['result']
            self._api_is_ready = True
        else:
            self._result = json.loads(msg)['result']
            self._ws.close()
            self.reset()

    @run_in_thread(0.01)
    def get_account_history(self, account_id, stop, limit, start):
        while not self._api_is_ready:
            time.sleep(0.01)
        self._send_msg([self._history_api_id, "get_account_history",
            [account_id, stop, limit, start]])

    @run_in_thread(0.01)
    def get_market_history(self, base_id, quote_id, ts, start, end):
        while not self._api_is_ready:
            time.sleep(0.01)
        self._send_msg([self._history_api_id, "get_market_history",
            [base_id, quote_id, ts, start, end]])

    @run_in_thread(0.01)
    def get_fill_order_history(self, base_id, quote_id, limit):
        while not self._api_is_ready:
            time.sleep(0.01)
        self._send_msg([self._history_api_id, "get_fill_order_history",
            [base_id, quote_id, limit]])

def scan_account(acc_id, max_len = 100):
    api = CybexHistoryAPI('wss://shanghai.51nebula.com')
    start = 0
    tot_len = 0
    while tot_len < max_len:
        print('start at 1.11.{}'.format(start))
        ret = api.get_account_history(acc_id, '1.11.1', 100, '1.11.' + str(start))
        if len(ret) == 0 or int(ret[0]['id'].split('.')[-1]) == start:
            break
        tot_len += len(ret)
        print('got {}'.format(len(ret)))
        print('end at {}'.format(ret[-1]['id']))
        #print(json.dumps(ret, indent=2))
        start = int(ret[-1]['id'].split('.')[-1]) - 1

    print(tot_len)
    return

def run_test():
    scan_account('1.2.38696')

if __name__ == '__main__':
    run_test()

Я получаю следующую ошибку:

Traceback (most recent call last):
File "ListenTransferRecord.py", line 197, in <module>
    run_test()
File "ListenTransferRecord.py", line 186, in run_test
    respone = scan_account(accountID,10)
File "ListenTransferRecord.py", line 147, in scan_account
    ret = api.get_account_history(acc_id, '1.11.1', 100, '1.11.' + str(start))
File "ListenTransferRecord.py", line 71, in __wrapper
    return self._result
AttributeError: 'CybexHistoryAPI' object has no attribute '_result'

Я не понимаю, почему он может хорошо работать в Windows, но не в Ubuntu.

И я попытался запустить простой код на моем VPS (ubuntu), чтобы проверить, в порядке ли среда python.

Я пробовал переустановить все модули этого импорта кода. Но это все еще не работает.

Вы устанавливаете self._result в свой метод on_message, это действительно срабатывает? Вы вводите то же самое в окнах?

Mark 31.10.2018 12:27

В on_message вы устанавливаете result на двух условиях. С другой стороны, в случае else вы устанавливаете self._result.

Klaus D. 31.10.2018 12:31

да, всего тот же код. ничего не меняя. Я просто копирую этот код в ubuntu и запускаю.

Cobb 31.10.2018 12:31
2
3
96
1

Ответы 1

Ошибка, которую вы получаете, просто вызывает ошибку, которая была там уже - self._result устанавливается только при определенном условии (в ветке else в методе on_message), но вы безоговорочно получаете доступ к ней в своем декораторе. По какой-то причине (которую мы не можем сказать без более подробной информации - на самом деле есть вероятность, что никто не может сказать, не тестируя код в вашей конкретной среде), вы никогда (пока) не наткнулись на этот случай при запуске кода в Window, но Сама ошибка не зависит от самой среды. Исправить здесь довольно просто: просто убедитесь, что для атрибута _result установлено значение всегда (в конечном итоге на какое-то контрольное значение, например None:

def on_message(self, ws, msg):
    print(msg)

    self._result = None # default value

    if self._login_api_id < 0:
        result = json.loads(msg)
        self._login_api_id = result['id']
        self._send_msg([self._login_api_id, "history", []])
    elif self._history_api_id < 0:
        result = json.loads(msg)
        self._history_api_id = result['result']
        self._api_is_ready = True
    else:
        self._result = json.loads(msg)['result']
        self._ws.close()
        self.reset()

Что касается того, почему у вас разное поведение в разных средах, это может происходить по такому количеству причин, что невозможно точно перечислить их все ... это может быть связано с задержкой в ​​сети и проблемами синхронизации между вашими потоками, деталями реализации конкретной ОС, фаза луны, что угодно, и, как я уже сказал, это в основном те проблемы, которые невозможно устранить без прямого доступа к обоим вашим средам.

Хотя задается только одно условие, но я думаю, что логика не проблема. Поток завершается, когда функция «_ws.close ()» выполняется в условии «else» в функции «one_massage». И в этом случае «_result» - это присваивание. Другое условие в "one_massage", theard все еще работает, поэтому функция "run_in_thread" ничего не вернет.

Cobb 31.10.2018 16:45

Что ж, полученная вами ошибка является доказательством того, что существует логическая ошибка (состояние гонки, что угодно), что бы вы ни думали. Параллельное программирование всегда сложно ...

bruno desthuilliers 31.10.2018 17:33

Я добавляю «return None» во все условия. но все та же ошибка.

Cobb 01.11.2018 02:06

Вы видели опубликованный мной фрагмент ??? Дело не в возврате None, а в том, чтобы убедиться, что атрибут установлен. Возвращение None, конечно же, не исправит это ...

bruno desthuilliers 01.11.2018 09:23

хотя я даю все условия с помощью «self._return = 'thingStr'», это все равно ошибка: нет атрибута '_result'. Это означает, что функция run_in_thread ничего не получает от websocket. Я отлаживаю этот код в ubuntu и обнаруживаю, что основной поток останавливается в «_ws.run_forever ()» , и никогда не перехожу к функции «on_open». затем сообщите об ошибке.

Cobb 01.11.2018 12:28

Я провожу тест. И обнаруживаем, что есть некоторая проблема функции: "run_forever". stackoverflow.com/questions/53100975/…

Cobb 01.11.2018 13:08

OK. Узнайте причину. Просто потому, что версия websockt отличается. Если у кого-то есть такие же удобства, как у меня, вы можете нажать на ссылку выше.

Cobb 01.11.2018 15:55

Другие вопросы по теме