I kind of know the syntax of asynchronous programming in F#. E.g.
let downloadUrl(url:string) = async {
let req = HttpWebRequest.Create(url)
// Run oper
The "async" in this example is not about concurrency or saving time, rather it's about providing a good programming model without blocking (read: wasting) threads.
If using other programming languages, typically you have two choices:
You can block, typically by calling synchronous methods. The disadvantage is that the thread is consumed and doing no useful work while it waits for the disk or network I/O or what have you. The advantage is it the code simple (normal code).
You can use callbacks to call asynchronously and get notifications when operations complete. The advantage is you don't block threads (these threads can be returned e.g. to the ThreadPool and a new ThreadPool thread will be used when the operation completes to call you back). The disadvantage is that a simple block of code gets divided up into a bunch of callback methods or lambdas, and it quickly becomes very complicated to maintain state/control-flow/exception-handling across the callbacks.
So you're between a rock and a hard place; you either give up the simple programming model or you waste threads.
The F# model gives the best of both worlds; you don't block threads, but you keep the straightforward programming model. Constructs like let! enable you to 'thread-hop' in the middle of an async block, so in code like
Blah1()
let! x = AsyncOp()
Blah2()
Blah1 may run on, say, ThreadPool thread #13, but then AsyncOp will release that thread back to the ThreadPool. Later when the AsyncOp completes, the rest of the code will start back up on an available thread (maybe, say, ThreadPool thread #20) which binds x to the result and then runs Blah2. In trivial client apps this rarely matters (except when ensuring you don't block the UI thread), but in server apps that do I/O (where threads are often a precious resource - threads are expensive and you can't waste them by blocking) non-blocking I/O is often the only way to make an application scale. F# enables you to write non-blocking I/O without having the program degrade into a mass of spaghetti-code callbacks.
See also
Best practices to parallelize using async workflow
How to do chained callbacks in F#?
http://cs.hubfs.net/forums/thread/8262.aspx