Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

After the program sends a character, it takes at least 100ms to read it #463

Closed
lbhzy opened this issue Oct 30, 2024 · 2 comments
Closed

Comments

@lbhzy
Copy link

lbhzy commented Oct 30, 2024

I'm writing a terminal emulator, use this library to create a program such as PowerShell,it takes at least 100ms to read the output of PowerShell,this causes the terminal to appear to be stuck when you press and hold the keyboard to send characters continuously.

Is there a way to reduce this time granularity?

My test code:

from PySide6.QtGui import *
from PySide6.QtCore import *
from PySide6.QtWidgets import *

import time
from winpty import PtyProcess

from terminal_base import Terminal


class LocalTerm(Terminal):
    """ 本地程序终端 """
    def __init__(self, prog: str, bg_img=None, scheme="Horizon Dark"):
        super().__init__(bg_img, scheme)

        self.timer = QTimer(self)
        self.timer.setSingleShot(True)
        self.timer.timeout.connect(self.timerCallback)

        try:
            self.proc = PtyProcess.spawn(prog, backend=1)
            # self.proc.fileobj.settimeout(0)
            self.proc.fileobj.setblocking(False)
            self.timer.start(10)
        except Exception as e:
            self.display(f"Exception: {e}\n")

    def close(self):
        self.proc.close(force=True)
        super().close()

    def sendData(self, data):
        self.proc.write(data)
        # print(f"s: {data}")

    t0 = 0
    def timerCallback(self):
        data = ''
        
        try:
            data = self.proc.read()
        except Exception:
            pass
        if data:
            # print(f"rx: {data.encode()}")
            print(f"{1000*(time.time() - self.t0):.2f}ms")
            self.t0 = time.time()
            self.display(data)
            self.timer.start(0)
        else:
            self.timer.start(10)


if __name__ == "__main__":

    app = QApplication()

    term = LocalTerm("powershell")
    term.show()

    app.exec()

press and hold the keyboard,result:

1730300119530.40ms
23.58ms
5461.32ms
513.86ms
97.16ms
93.91ms
112.06ms
95.99ms
92.32ms
105.80ms
103.05ms
@andfoy
Copy link
Owner

andfoy commented Oct 31, 2024

Hi @lbhzy, thanks for reaching out, this is a well-known issue on winpty-rs: andfoy/winpty-rs#75. (see https://github.com/andfoy/winpty-rs/blob/174030c0f363084935452aeb78e37a0ccb383b59/src/pty/base.rs#L412 for the relevant wait).

An user tried to fix it (andfoy/winpty-rs#76), however, the proposed fix caused the PTY process to deadlock, as multiple threads try to access the same pipe natively. Given that such pipes are synchronous in nature, any I/O operation performed from Windows can block (see https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-peeknamedpipe#remarks). An important remark is that using locks won't fix the underlying block.

As the regression introduced by the performance improvement caused deadlocks, I decided to rollback the change, and at the moment, the 100ms delay is expected. Recently an update (microsoft/terminal#17510) to add support for overlapped I/O took place in ConPTY, however, the changes at the moment haven't been upstreamed yet, and it could take up to another month to be available (subject to updates).

However, we could build ConPTY from scratch, according to https://github.com/microsoft/terminal?tab=readme-ov-file#developer-guidance and bundle it with the library.

@lbhzy
Copy link
Author

lbhzy commented Nov 1, 2024

Thank you for your answer,I'll wait for the update to come

@lbhzy lbhzy closed this as completed Nov 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants