Marko Rauhamaa <ma...@pacujo.net> wrote: > Other points: > > * When you wake up from select() (or poll(), epoll()), you should treat > it as a hint. The I/O call (accept()) could still raise > socket.error(EAGAIN). > > * The connections returned from accept() have to be individually > registered with select() (poll(), epoll()). > > * When you write() into a connection, you may be able to send only part > of the data or get EAGAIN. You need to choose a buffering strategy -- > you should not block until all data is written out. Also take into > account how much you are prepared to buffer. > > * There are two main modes of multiplexing: level-triggered and > edge-triggered. Only epoll() (and kqueue()) support edge-triggered > wakeups. Edge-triggered requires more discipline from the programmer > but frees you from having to tell the multiplexing facility if you > are interested in readability or writability in any given situation. > > Edge-triggered wakeups are only guaranteed after you have gotten an > EAGAIN from an operation. Make sure you keep on reading/writing until > you get an EAGAIN. On the other hand, watch out so one connection > doesn't hog the process because it always has active I/O to perform. > > * You should always be ready to read to prevent deadlocks. > > * Sockets can be half-closed. Your state machines should deal with the > different combinations gracefully. For example, you might read an EOF > from the client socket before you have pushed the response out. You > must not close the socket before the response has finished writing. > On the other hand, you should not treat the half-closed socket as > readable. > > * While a single-threaded process will not have proper race conditions, > you must watch out for preemption. IOW, you might have Object A call > a method of Object B, which calls some other method of Object A. > Asyncio has a task queue facility. If you write your own main loop, > you should also implement a similar task queue. The queue can then be > used to make such tricky function calls in a safe context. > > * Asyncio provides timers. If you write your own main loop, you should > also implement your own timers. > > Note that modern software has to tolerate suspension (laptop lid, > virtual machines). Time is a tricky concept when your server wakes up > from a coma. > > * Specify explicit states. Your connection objects should have a data > member named "state" (or similar). Make your state transitions > explicit and obvious in the code. In fact, log them. Resist the > temptation of deriving the state implicitly from other object > information. > > * Most states should be guarded with a timer. Make sure to document for > each state, which timers are running. > > * In each state, check that you handle all possible events and > timeouts. The state/transition matrix will be quite sizable even for > seemingly simple tasks.
And exactly how is getting all of this correct any easier than just using threads and blocking i/o? I'd like to see the programmer who can get all of this correct, but has no idea how to use a queue og mutex without deadlocking. Sturla -- https://mail.python.org/mailman/listinfo/python-list