Overview of Blocking vs Non-Blocking

In Bnlang, an operation is either blocking or non-blocking:

  • Blocking — the program waits in place until the operation finishes. The rest of the script (and the event loop) is paused.
  • Non-blocking — the program kicks off the operation, keeps running, and the runtime calls your callback later when the result is ready.

Most stdlib modules ship both styles. As a rule of thumb, the sync variant is named fn() and the async variant is fn_async().


Blocking Example

io.read_file blocks until the whole file is in memory. This is fine for small files or one-off scripts.

import "io" as io;

print("start");
var data = io.read_file("notes.txt");   // blocks here
print("file length:", data.byte_length);
print("end");

Non-Blocking Example

io.read_file_async returns immediately; the callback fires when the read is done. The lines after it keep running in the meantime.

import "io" as io;

print("start");
io.read_file_async("notes.txt", function (err, data) {
    if (err != null) { print("read failed:", err); return; }
    print("file length:", data.byte_length);
});
print("scheduled, doing other work");

Streaming Large Files

For very large files, neither read_file nor read_file_async is the right choice — both load the whole thing into memory. Use io.open_read to get a stream you can pull from in chunks. The callback receives chunk = null to signal EOF.

import "io" as io;

var src = io.open_read("big.log");

function on_chunk(err, chunk) {
    if (err != null) { print("read err:", err); return; }
    if (chunk == null) {
        print("done");
        src.close();
        return;
    }
    print("got", chunk.byte_length, "bytes");
    src.read(64 * 1024, on_chunk);
}

src.read(64 * 1024, on_chunk);

Why Non-Blocking Matters

  • Keeps a web server, GUI, or CLI responsive while I/O is in flight.
  • Lets multiple slow operations (network calls, DB queries, file ops) make progress at the same time.
  • Avoids head-of-line blocking when one slow request would otherwise hold up everyone else.

Best Practices

  • Default to the async variant in long-running programs (servers, daemons).
  • Reach for the sync variant in scripts, build steps, or REPL exploration where simplicity beats throughput.
  • Don't mix heavy CPU work into your async callbacks — they share the event-loop thread with every other request.