интерпретатор python висит в канале paramiko __del__ - PullRequest
0 голосов
/ 18 сентября 2018

Я столкнулся с проблемой, когда интерпретатор python зависает во время выключения.Я использовал py-spy (https://github.com/benfred/py-spy), чтобы собрать трассировку стека для всех потоков, когда он зависал, и получил следующее:

    Thread 0x7F5F2E3DB700 (idle)
    Thread 0x7F5F6416C700 (idle)
    Thread 0x7F5F6376B700 (idle)
    Thread 0x7F5F6C379700 (active)
            __bootstrap_inner (threading.py:831)
            __bootstrap (threading.py:774)
    Thread 0x7F600380A700 (active)
            accept (socket.py:206)
            accept (rpyc/utils/server.py:128)
            start (rpyc/utils/server.py:241)
            run (threading.py:754)
            __bootstrap_inner (threading.py:801)
            __bootstrap (threading.py:774)
    Thread 0x7F6025F76700 (active)
            close (paramiko/channel.py:638)
            __del__ (paramiko/channel.py:130)

Я считаю, что проблема связана с последнейиз этих стеков (которые, я думаю, могут быть основным потоком).

    Thread 0x7F6025F76700 (active)
            close (paramiko/channel.py:638)
            __del__ (paramiko/channel.py:130)

Сервер, на котором я выполнял код, использовал python2.7 и paramiko 2.4.1. Просмотр соответствующих строккод в paramiko, он пытается захватить блокировку как часть закрытия канала:

     def close(self):
            """
            Close the channel.  All future read/write operations on the channel
            will fail.  The remote end will receive no more data (after queued data
            is flushed).  Channels are automatically closed when their `.Transport`
            is closed or when they are garbage collected.
            """
            self.lock.acquire()
            try:
                # only close the pipe when the user explicitly closes the channel.
                # otherwise they will get unpleasant surprises.  (and do it before
                # checking self.closed, since the remote host may have already
                # closed the connection.)
                if self._pipe is not None:
                    self._pipe.close()
                    self._pipe = None

                if not self.active or self.closed:
                    return
                msgs = self._close_internal()
            finally:
                self.lock.release()
            for m in msgs:
                if m is not None:
                    self.transport._send_user_message(m)

Строка 638 является self.lock.acquire (). Я не думаю, что блокировка получается извне класса в любой точке, и каждый раз, когда блокировка приобретается в классе, она выглядит как освобождаемая в окончательной ветви.

Есть ли что-то странное, что происходит здесь как часть выключения?

...