jupyter / notebook

Jupyter Interactive Notebook
https://jupyter-notebook.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
11.71k stars 4.95k forks source link

STDIN prompts rendering is nondeterministic with respect to stream outputs #3159

Open CSEMike opened 6 years ago

CSEMike commented 6 years ago

I believe the Jupyter FE is receiving STDIN and stream messages in a nondeterministic order.

Here's a small repro:

import getpass, sys
print (2)
sys.stdout.flush()
_ = getpass.getpass()

I would expect this to render 2 before the getpass prompt in all executions. Yet, if I execute this a few times, I occasionally see the reverse order. (Perhaps 1-2 instances in 10 executions.)

Example screenshot: screenshot2

My conjecture is that what is happening is that STDIN channel messages and IOPUB messages are not deterministically ordered for a given cell execution.

takluyver commented 6 years ago

I think your conjecture is on the mark. I don't know if there's an easy way to solve this, though.

Kai-Chen commented 6 years ago

I'd like to take a look at what's causing this problem. Any hint at which part of the code base should I look into?

jasongrout commented 6 years ago

The first thing I'd do is try to reproduce the problem and look in the browser debugger to check the order of messages coming into the browser. If it is indeed the message order that is messed up, then the problem is likely in the python side. If the order of the messages is okay, but we still see them in the wrong order, the problem is in the javascript.

Kai-Chen commented 6 years ago

I was having trouble reproducing the problem, till I added a clear_output() call (see sample code below).

And it's the server messages that's out of order (see attached screenshots)

Which part of the python code should I look into next?

Sample code

from IPython.display import clear_output

def get_player_input(banner):
    while True:
        clear_output()
        print(banner)
        choice = input(f'(H)it, (S)tand, or (Q)uit: ').upper()
        if choice == 'H' or choice == 'S' or choice == 'Q':
            return choice

choice = ''
while choice != 'Q':
    choice = get_player_input('Welcome to Blackjack!')
    print(f'You chose {choice}')

Message Order

input-request

stream

System Information

kai@sccdev01(0)% uname -a
Linux sccdev01 4.18.12-arch1-1-ARCH #1 SMP PREEMPT Thu Oct 4 01:01:27 UTC 2018 x86_64 GNU/Linux
kai@sccdev01(0)% jupyter-notebook --version
5.5.0
kai@sccdev01(0)% python --version
Python 3.7.0
sergenti commented 1 year ago

any news? this is so weird

jasongrout commented 1 year ago

Interestingly, I can reproduce the issue with Michael's code on classic notebook (happened about 4 times in 100 tries), but I executed his code block 150 times on JupyterLab and didn't see the issue at all.

I think Michael correctly diagnosed the issue, and my guess is that the root problem is that messages on different zmq channels are not deterministically ordered between channels. One idea: since each message has a timestamp, perhaps we can use the timestamp to guide us in ordering messages across different zmq channels from the same kernel (if the timestamp has high enough resolution). Or more deterministically, we could introduce a message counter in message metadata.