surprising on the author' machine ( dual-core ghz macbook)the average response time (measured over , requestsfor the coroutine-based server is about ms versus ms for threads this difference is explained by the fact that the coroutinebased code is able to respond as soon as it detects connection whereas the threaded server doesn' get to run until it is scheduled by the operating system in the presence of cpu-bound thread and the python global interpreter lockthe server may be delayed until the cpu-bound thread exceeds its allotted time slice on many systemsthe time slice is about ms so the above rough measurement of thread response time is exactly the average time you might expect to wait for cpu-bound task to be preempted by the operating system the downside to polling is that it introduces significant overhead if it occurs too often for instanceeven though the response time is lower in this examplethe program instrumented with polling takes more than longer to run to completion if you change the code to only poll after every six-pack of beerthe response time increases slightly to ms whereas the run time of the program is only greater than the program without any polling unfortunatelythere is often no clear-cut way to know how often to poll other than to make measurements of your application even though this improved response time might look like winthere are still horrible problems associated with trying to implement your own concurrency for exampletasks need to be especially careful when performing any kind of blocking operation in the web server examplethere is fragment of code that opens and reads data from file when this operation occursthe entire program will be frozen--potentially for long period of time if the file access involves disk seek the only way to fix this would be to additionally implement asynchronous file access and add it as feature to the scheduler for more complicated operations such as performing database queryfiguring out how to carry out the work in an asynchronous manner becomes rather complex one way to do it would be to carry out the work in separate thread and to communicate the results back to the task scheduler when available--something that could be carried out with careful use of message queues on some systemsthere are low-level system calls for asynchronous / (such as the aio_family of functions on unixas of this writingthe python library provides no access to those functionsalthough you can probably find bindings through third-party modules in the author' experienceusing such functionality is lot trickier than it looks and is not really worth the added complexity that gets introduced into your program--you're often better off letting the thread library deal with such matters socket the socket module provides access to the standard bsd socket interface although it' based on unixthis module is available on all platforms the socket interface is designed to be generic and is capable of supporting wide variety of networking protocols (internet,tipcbluetoothand so onhoweverthe most common protocol is the internet protocol (ip)which includes both tcp and udp python supports both ipv and ipv although ipv is far more common it should be noted that this module is relatively low-levelproviding direct access to the network functions provided by the operating system if you are writing network applicationit may be easier to use the modules described in or the socketserver module described at the end of this lib fl ff