Re: Asyncronous IO
Hi Konrad, sufficently abstract the URL space from the physical disk. Most other mature frameworks allow your to creat a completly virtual url space which has no relation to physical files on disk. The way the forms.l maps a full path to its javascript file and puts it in the output Hmm, which path do you think of? There is only one .js file referenced in form.l, and it appears as src=http://localhost/8080/lib/form.js; makes me particularly uncomfortable as it is exposing data on where I have installed picolisp. so the only path that is exposed is lib/. Where do you see the installation path? In general, the GUI only uses relative paths anyway. (note: the /8080/ is not part of the path, but the port encoded for httpGate). Cheers, - Alex -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Asyncronous IO
Sounds clever, but very complicated maybe to maintain the scheduling? You mentioned multiplayer online games as a possibility, are the big ones with thousands of simultaneous users already operating under these principles? It would be great if you could point me to a resource on the basics behind this way of doing things. /Henrik -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Asyncronous IO
Henrik, take a look at http://docs.python.org/library/asyncore.html There is even a few samples. I have used this extensively, reimplemented it directly in C a time or two. I think it would be relatively simple to implement using 'task' and '*Run'. Rand Henrik Sarvell wrote: Sounds clever, but very complicated maybe to maintain the scheduling? You mentioned multiplayer online games as a possibility, are the big ones with thousands of simultaneous users already operating under these principles? It would be great if you could point me to a resource on the basics behind this way of doing things. /Henrik -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Asyncronous IO
On Wed, Oct 08, 2008 at 09:55:16PM +1100, konrad Zielinski wrote: I belive the issue is that I have actually installed picoLisp under usr/local but don't use it exclusivly from that directory. As such I Ah, yes, in that case the path gets expanded. I didn't think about that, because I always use it locally, with relative paths. Cheers, - Alex -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Asyncronous IO
Konrad, Thanks for the links and clarifications, here is another one: http://en.wikipedia.org/wiki/Twisted_(software) However, for really understanding what this is about this link that you posted is very good: http://www.nightmare.com/medusa/medusa.html From the above Medusa link: Most Internet servers are built on a 'forking' model.. It never states that this is in fact the case with Apache but I get the feeling that this is in fact how Apache works, at least the 1.x version which didn't do threading. If this is the case then why is Apache the de facto standard? From the Medusa page one gets the impression that forking is horribly inefficient compared to the asynchronous way, but if this really was the case an alternative to Apache based on this model would surely have strong support. There is something missing here and I can't get that missing piece. Please enlighten me. Could this maybe be an explanation: A high-load server thus needs to have a lot of memory. Many popular Internet servers are running with hundreds of megabytes of memory.. Hundreds of megabytes was maybe a lot at time of writing but is nothing now. Maybe technological advancements simply solved the whole problem on the http side? If I can be convinced that I'm not solving a non-existent problem then I would be happy to help you with this if you want help. /Henrik -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Asyncronous IO
For even more discussions, look at http://www.acme.com/software/ and then mini_httpd, micro_httpd, thttpd. These are really lightweight http servers. He did a lot of work comparing threading, forking, and async IO. Async IO wins big for http serving. Apache just happened to be at the right place at the right time, it is by far NOT the most efficient http server. Apache 1 was only forking. With modern UNIX memory management, forking is (was) not that expensive, and Apache performed well. Today, apache has a zillion mod_* stuff, but even that is just to speed up inefficiencies. I really prefer NOT to put up apache, unless my customer forces me to do so. Most other servers perform better than apache, but apache is just out there. I started my work with python and medusa, one day switched to asyncore, and then found picolisp. I WILL NOT be going back. It would be very interesting to have a non-threading, non-forking model in picolisp based on 'task'. The more I think about it, it really is simple. One just needs to get your head around the concepts first and then around 'task'. Picolisp also forks, but for other reasons, the main one, it is completely integrated with it's database. A lightweight async 'task' model would indeed be an interesting alternative. If this is the case then why is Apache the de facto standard? From the Medusa page one gets the impression that forking is horribly inefficient compared to the asynchronous way, but if this really was the case an alternative to Apache based on this model would surely have strong support. There is something missing here and I can't get that missing piece. Please enlighten me. Apache JUST HAPPENED to be there when http serving took off. At that moment in history, it was the best available solution. Apache is where it is today for the same reason that Microsoft is where it is. A happenstance of history. Just like Linux won out over BSD. BSD was entangled in a lawsuit with ATT at a critical junction of time, and Linux took off. Had it not been for the ATT / Berkeley lawsuit, I do not believe we would have ever heard the word Linux. Well some of us would have - I was doing kernel work in 1991 when Linus released the first code. Of course we looked at it - and quickly said, no, let's use BSD - then in 1992 ATT screwed themselves with the lawsuit. Do you hear much about Bell Labs these days? They do still exist. Rand -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Asyncronous IO
Ahh, I belive the issue is that I have actually installed picoLisp under usr/local but don't use it exclusivly from that directory. As such I get the following: script src=http://localhost:8080//usr/local/picoLisp/lib/form.js; type=text/javascript/script which includes an absolure path to forms.js regards Konrad On 08/10/2008, Alexander Burger [EMAIL PROTECTED] wrote: Hi Konrad, sufficently abstract the URL space from the physical disk. Most other mature frameworks allow your to creat a completly virtual url space which has no relation to physical files on disk. The way the forms.l maps a full path to its javascript file and puts it in the output Hmm, which path do you think of? There is only one .js file referenced in form.l, and it appears as src=http://localhost/8080/lib/form.js; makes me particularly uncomfortable as it is exposing data on where I have installed picolisp. so the only path that is exposed is lib/. Where do you see the installation path? In general, the GUI only uses relative paths anyway. (note: the /8080/ is not part of the path, but the port encoded for httpGate). Cheers, - Alex -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED] -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Asyncronous IO
Henrik, all of the references I'm aware of are based on Python. the standard Python library includes modules called asyncore and asynchat (sections 17.5 and 17.6 of the Python documentation. The original Asyncronous webserver (as far as I'm aware) is medusa http://www.nightmare.com/medusa/ http://www.amk.ca/python/code/medusa Twisted is a more mature (read complex) implementation of the same thing. At this stage i belive they have reimplemented everything and don't even use the standard asyncore module anymore. I use teisted at work and from the application developers point of view the system allows complex applications to be built in very neat small peices. The approach has the advantage of not having the same kind of concurrency issues as threaded code has. By definition asyncronous code is only doing one thing at a time, so there is no danger of two functions accessing the same data objects at the same time, without the need for stemapors or locks. I believe that the Erlang language uses a similer approach to implement its light weight processes, and it allows them to scale to thousands of processes. regards Konrad On 08/10/2008, Henrik Sarvell [EMAIL PROTECTED] wrote: Sounds clever, but very complicated maybe to maintain the scheduling? You mentioned multiplayer online games as a possibility, are the big ones with thousands of simultaneous users already operating under these principles? It would be great if you could point me to a resource on the basics behind this way of doing things. /Henrik -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED] -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Asyncronous IO
Henrik Sarvell wrote: Thanks Randall for that! So where do we start, where do I start, am I needed? I just don't have time now to really look into it. :-( Is the best way to simply review the Twisted source and reimplementing in Pico, keeping the OODB in mind all the time maybe? I would look at the simplest example, Medusa, first. -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Asyncronous IO
Hi Konrad and Henrik, Is the best way to simply review the Twisted source and reimplementing in Pico, keeping the OODB in mind all the time maybe? reading from http://en.wikipedia.org/wiki/Twisted_(software) Twisted supports an abstraction over raw threads=E2=80=94using a thread = as a deferred source. How threads fit in the Twisted framework? I thought that Konrad's idea was not to use threads or processes at all? In case of forking, it is as efficient to use processes as using threads, at least on Linux, as Rand already mentioned. The advantage of picoLisp is that the processes are small, say 3MB so you can have many sessions and fork many times before you run out of memory. This is very hard to achieve with Common Lisp implementations (or Java) for example, so people there need threads with their monster process. I do not think Konrad could achieve single process/thread http server without a bit of coding in C. PicoLisp I/O operations block I think and that is not good for this problem. It would be at least hard to make sure no operation blocks the process. Maybe the best or most pragmatic way is splitting your web app into a static files part that can be served by a specialized web server, e.g. thttpd or nginx and a dynamic part served by picolisp. It would be nice to see Konrad's aim come true though;-) Cheers, Tomas -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Asyncronous IO
Hi Tomas, I do not think Konrad could achieve single process/thread http server without a bit of coding in C. PicoLisp I/O operations block I think Not necessarily. If we use the select() mechanism provided by '*Run' and 'task', you can make input operations like 'listen', 'accept', 'read', 'rd' etc. non-blocking. In addition, I sometimes use the 'alarm' function (in combination with 'catch', 'throw' and 'finally') to ensure that no operation takes too long. Maybe the best or most pragmatic way is splitting your web app into a static files part that can be served by a specialized web server, You do not need a specialized web server for that. A .html file will be directly sent to the client, without any forking. And also .l files do not automatically cause the fork, but only if (app) is called during their execution. For the (now obsolete) 7fach web portal the whole initial processig consisted of non-forking pages (static html-files and dynamically generated contents), and only when the user went to the login page it happened that (app) was called. Cheers, - Alex -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
picoWiki
Hi all, I am implementing a wiki in picoLisp, see http://logand.com/picoWiki Do you think it would be useful for the picoLisp comunity (can we call it that way yet?) to have a wiki with publicly editable info about picoLisp and related stuff? If yes, any ideas and/or content contributions welcome;-) Cheers, Tomas -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Asyncronous IO
Hi Alex, In addition, I sometimes use the 'alarm' function (in combination with 'catch', 'throw' and 'finally') to ensure that no operation takes too long. I don't think alarm is good enough though. It is good for timeouts but not for schedulling. BTW: I found a typo in http://www.software-lab.de/refD.html#alarm which should be http://www.software-lab.de/refA.html#alarm Not necessarily. If we use the select() mechanism provided by '*Run' and 'task', you can make input operations like 'listen', 'accept', 'read', 'rd' etc. non-blocking. How would this work, could you provide a simple example? How would I know that 'read' does not have data available, or only part of the data is available? If I just use alarm (or maybe something with smaller granularity) I would be wasting precious time on timeouts. Cheers, Tomas -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Asyncronous IO
Hi Tomas, I don't think alarm is good enough though. It is good for timeouts but not for schedulling. True. I would not use if for scheduling, though, but to terminate operations which might possibly take too long (e.g. 'connect' to another server). BTW: I found a typo in http://www.software-lab.de/refD.html#alarm which should be http://www.software-lab.de/refA.html#alarm Thanks! I fixed it in the testing release. Not necessarily. If we use the select() mechanism provided by '*Run' and 'task', you can make input operations like 'listen', 'accept', 'read', 'rd' etc. non-blocking. How would this work, could you provide a simple example? I posted some examples in my initial response to Konrad yesterday (Message-ID: [EMAIL PROTECTED]). For a single port, this could be (task (port ) # Listen on port (when (accept @) # A connect arrived (task @ # Install another task on this socket Sock @ # Keep the socket in the task's env (in Sock # Data arrived on that socket (if (rd) # read them (out Sock (eval @)) # Do something with the data (task Sock) # else we got EOF (close Sock) ) ) ) ) ) # and close the connection This mechanism allows an arbitrary number of connections on port . I have this mechanism very often for communication between different systems. For communication with a browser you would better use (line) instead of (rd), and send HTML-data instead of (eval @). How would I know that 'read' does not have data available, or only part of the data is available? For the above communication between my own machines, I can guarantee that no message received with the (rd) is longer than the system pipe buffer size (at least 4096 bytes, larger on most systems). In that case the (rd) will never block if select() said that data are available. If you receive data from a browser, they may be larger. But I think this will never make problems if you always read reasonable chunks (e.g. chunked transfers, or character by character to be absolutely sure) in a single step in the 'task' body. select() will either return immediately when more data are available, or will not call the 'task' body, so nothing will actually block. If I just use alarm (or maybe something with smaller granularity) I would be wasting precious time on timeouts. Yes. So alarm is always just an additional security measure. Cheers, - Alex -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: picoWiki
Hi Tomas, I am implementing a wiki in picoLisp, see http://logand.com/picoWiki Good idea! However, I did not succeed to connect (yet?). Do you think it would be useful for the picoLisp comunity (can we call it that way yet?) Hehe, perhaps better call it a com-mini-ty ;-) Cheers, - Alex -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: picoWiki
http://logand.com/picoWiki Ah, now it works! Seems I just had a temporary network problem. Cheers, - Alex -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: picoWiki
Hi Alex, Good idea! However, I did not succeed to connect (yet?). I just tried with w3m, looks like w3m messes up the relative links, e.g. if I am at http://logand.com/picoWiki and have a relative link a class=i href=?ChangesChanges/a, w3m will interpret it as http://logand.com/?Changes. It works in Firefox though, i.e. it opens http://logand.com/picoWiki?Changes page as intended. I'll think how to do the links better. Thanks, Tomas -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Asyncronous IO
Hi all, oops, sorry! Forget what I wrote: A .html file will be directly sent to the client, without any forking. And also .l files do not automatically cause the fork, but only if (app) is called during their execution. This was wrong. The 'server' function in lib/http.l will always fork when a connection request arrives. It is just that the child process immediately terminates after serving the connection (unless (app) was called). BTW, as a matter of an example, the 'server' function in lib/http.l *does* implement a non-forking server, but only in the child process once the initial connect from a client has created a session: ... (loop # Main loop in the parent process (setq *Sock (listen P))# Wait for a request (NIL (fork) (close P)) # The child closes 'P' and exits the loop (close *Sock) )# The parent closes the new connection and continues (task *Sock (http @)) # The child installs a task on that socket (http *Sock) # and serves the first page (or *SesId (bye)) # If (app) was not called, terminate (task *Sock # Else install a task for the new session socket (when (accept *Sock) # Accept requests on that socket (task @ (http @)) # without forking (http @) ) ) ) Note: This uses in two places a construct of the form (task socket (http socket)) (http socket) The reason for that is that for HTTP/1.1 more than one transaction may be done before the connection is closed. Hope this helps. Cheers, - Alex -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Asyncronous IO
Hi All, In the matter of how to begin. Twisted is I think the wrong place. It is a very large and complicated beast which has grown in its own unquie direction. So much so that it is incompatable with a lot of standard python tools and libraries, uses its own logging system etc. In copying python the place to start are Asyncore and Asynchat. The Medusa pages had some basic examples of building an asyncronous client and then an asyncronous proxy. I intend to try to build these things and satisfy myself that I'm really getting asyncronous behaviour. After that I'm thinking that a good proof of concept application would be a basic instant messanger which allows multiple users to connect and send messages to each other. this is a nice application which has shared state without needing a particularly fancy interface. As this is a personal project, I'm happy to share code, questions and comments through this list if there is interest. A similer Tic Tac Toe server which allows multiple simultainous games and routes moves to the correct clients would also be nice. Then its on to the main event. where more care is needed in working out what functions are needed and how additional functionality should be hooked into the system. Here I would be aiming to build a generic UDP and TCP server that is as adaptable as Medusa and Twisted. At this point, if there is enough interest. putting code on Sourceforge or Google code might be worth while. Heck it might even give pico Lisp some extra publicity. (I note this list has been getting a little more lively lately, which is a good sign). And can be used as a base for any protocol anyone chooses to throw at it. One reason why the Async approach is well suited to python is due to limitations in the Python interpreter. Python has something called a Global interpreter lock, which restricts it to using a single CPU, even if threading primitives are used. Ergo threading primities become an overhead which increases code complexity without giving increased scalability. I believe that picoLisp has similer single CPU limitation, I'm pretty sure that there are no threading primitives. So the only possible choices are Asyncronous or Forking. The latter makes shared state somewhat difficult to manage, and exists allready (so there is nothing new to build). 2008/10/9 Alexander Burger [EMAIL PROTECTED]: Hi all, oops, sorry! Forget what I wrote: A .html file will be directly sent to the client, without any forking. And also .l files do not automatically cause the fork, but only if (app) is called during their execution. This was wrong. The 'server' function in lib/http.l will always fork when a connection request arrives. It is just that the child process immediately terminates after serving the connection (unless (app) was called). BTW, as a matter of an example, the 'server' function in lib/http.l *does* implement a non-forking server, but only in the child process once the initial connect from a client has created a session: ... (loop # Main loop in the parent process (setq *Sock (listen P))# Wait for a request (NIL (fork) (close P)) # The child closes 'P' and exits the loop (close *Sock) )# The parent closes the new connection and continues (task *Sock (http @)) # The child installs a task on that socket (http *Sock) # and serves the first page (or *SesId (bye)) # If (app) was not called, terminate (task *Sock # Else install a task for the new session socket (when (accept *Sock) # Accept requests on that socket (task @ (http @)) # without forking (http @) ) ) ) Note: This uses in two places a construct of the form (task socket (http socket)) (http socket) The reason for that is that for HTTP/1.1 more than one transaction may be done before the connection is closed. Hope this helps. Cheers, - Alex -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED] -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Asyncronous IO
Hi Alex, Not necessarily. If we use the select() mechanism provided by '*Run' and 'task', you can make input operations like 'listen', 'accept', 'read', 'rd' etc. non-blocking. select() does not make thinks non-blocking as far as I am aware. It just wakes up the process when something is going on. I think that to be non-blocking, all I/O operations must be able to say how much data to read/write without blocking. I posted some examples in my initial response to Konrad yesterday (if (rd) # read them (out Sock (eval @)) # Do something with the data I think these two lines are the problematic ones. I have this mechanism very often for communication between different systems. For communication with a browser you would better use (line) instead of (rd), and send HTML-data instead of (eval @). Does not (line) try to read until eol or eof? That could block if the client is naughty or something happens (like delay while receiving the line and being in the middle of it). Also, http://www.software-lab.de/refL.html#line says Note that a single carriage return may not work on network connections, because the character look-ahead to distinguish from return+linefeed can block the connection. How would I know that 'read' does not have data available, or only part of the data is available? For the above communication between my own machines, I can guarantee that no message received with the (rd) is longer than the system pipe buffer size (at least 4096 bytes, larger on most systems). In that case the (rd) will never block if select() said that data are available. How can you guarantee that? Simply by sending little data or some special protocol? Also, that is a very special case. I don't think you can make such assumptions with HTTP server where you don't have the clients under control. If you receive data from a browser, they may be larger. But I think this will never make problems if you always read reasonable chunks (e.g. chunked transfers, or character by character to be absolutely sure) in a single step in the 'task' body. select() will either return immediately when more data are available, or will not call the 'task' body, so nothing will actually block. How big is a reasonable chunk? What if something happens (a delay) with the client in the middle of sending the chunk? Would not reading by character loose the magic of striving for supercalifragilisticexpialidoucious server?;-) Also, not blocking is only a part of the story, what about schedulling? If two people share a computer say with MS-DOS, one must go for a coffee and wait until the other one finished. If they use UNIX, they can work simultaneously because the system splits the time between them in tiny chunks which they don't notice. The non-forking server in picolisp is of the first kind. Once the server is serving a request, everything else (all the other requests) have to wait until it is finished with the current task. Cheers, Tomas -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Asyncronous IO
Hi Alex, thanks for the explanation! Tomas -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]
Re: Asyncronous IO
Hi Alex, your response to Tomas's questions dosn't seem to have made it to the list. Most of the documentation I have seen seems to suggest that Sockets need to be put into non blocking mode explicitly, ie using select() is not sufficent. At a low level attempting to read from a nonblocking socket will return a Would Block error condition. Is the picoLisp socket and task code allready setting sockets into non blocking mode? regards Konrad. 2008/10/9 Tomas Hlavaty [EMAIL PROTECTED]: Hi Alex, thanks for the explanation! Tomas -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED] -- UNSUBSCRIBE: mailto:[EMAIL PROTECTED]