Posts

Showing posts with the label Concurrency

[Node.js] Pending HTTP requests lead to unresponsive nodeJS

This is a recap conclusion to the potential problems of a NodeJS program I worked on previously. The program simulates thousands of clients navigating a website by sending thousands of http requests to a given API . The idea is to load test a particular API to make sure they can handle high traffic. Because we are simulating clients, it's important to keep track of the state of the simulated client as well. The problem with this program is it is buggy and becomes unresponsive from time to time (the only solution is to restart it). The problem was fixed by re-writing the entire program in Java, but it was regretful that I never had enough time to find the exact reason the nodeJS version of it failed. The following are potential causes I suspect: 1. Exceptions The NodeJS program was not written very neatly and stacked callbacks on top of callbacks on top of callbacks. This made it very difficult to keep track of exceptions and unexpected http responses are prone to happen. So...

[Node.js] MultiThreading & Worker Threads

1) NodeJS is single threaded, right? Prior to the introduction of worker threads (in ver.10.5.0), the answer is - Kind of . NodeJS run things in parallel, but programmatically,  the developer doesn't implement threads. Threads are automatically managed by libuv when we execute asynchronous operations, eg. I/O operations. Together with the use of callback functions, NodeJS achieves concurrency . 2) So what is the problem? CPU-intensive tasks The single-threaded model is great if all we do is asynchronous operations . Without worker thread support, any high CPU-intensive tasks will block the single-threaded event loop , because it is single-threaded - meaning it will wait for 1 task to complete before executing the next one. This scenario makes NodeJS not concurrent. 3) Multi-Processing Actually, it is technically possible to do multi-threading without worker threads. We can spawn child processes by forking to achieve multi-threading (arguably). But processes are expensive an...

[Java] Volatile

1) Volatile Used as an indicator to Java Compiler and Thread to not cache value of this variable and always read it from the main memory . In multi-threaded environment, threads might cache variables locally. Volatile (or synchronization) ensures the variable is read from main memory. Makes variable atomic by implementation.  Only possible with variables ; cannot be used with method or class (illegal operation) Guarantees visibility and ordering; write to any volatile variable happens before any read. Prevents compiler or JVM form reordering code or moving away them away form synchronization barrier.  2) Example private boolean bExit ; while (! bExit ) { checkUserPosition (); updateUserPosition (); } The focus here is the variable, bExit.  One Thread (Game Thread) can cache the value of bExit instead of getting it form main memory everytime. If in between, any other thread (Event handler thread) changes the value; it would...

[Synchronization - Java] Reentrant Locks vs Synchronized

Image
1) Reentrant Lock Implementation of Lock interface.  Mutually-exclusive lock (similar to synchronized) with extended feature like fairness. Lock is acquired via lock() and is held until unlock() 2) Reentrant Lock vs Synchronized 2.1) Blocking Indefinitely vs Temporarily/Selectively. Main difference is reentrant lock has the ability to try to lock interruptibly and with timeout. tryLock() allows program to try the lock without being blocked. In summary, Thread doesn't need to blocked indefinitely, whereas synchronized block block indefinitely. 2.2) Fairness Supported by Reentrant lock, but not by synchronized. 2.3) Get List of Threads waiting for Lock Reentrant locks have ability to see all threads waiting on the lock; accessible via API. 3) Cons of Reentrant Lock 3.1) Readability Requires wrapping in try-finally block, which makes code unreadable and hides business logic. 3.2) Potential Bugs Programmer is now responsible for acquiring and releasing loc...

[Threads - Java] What's the max number of threads I should use?

1) Start Approach The short and quick answer is to have # threads = CPU/Cores. Why have a thread if there's nothing to run it? Therefore, one thread per process/core will maximize processing power and minimize context switching. This assumption is a good starting approach . public static final int THREADS = Runtime . getRuntime (). availableProcessors (); 2) Detailed Approach: CPU-bound or I/O bound? But the more correct answer is - it depends if your task is  CPU-bound or I/O-bound? 2.1) I/O-bound If your thread has to wait for network packet or disk block, then CPU time is wasted waiting. In this case, you will want to consider having more threads per process, as your program can work on another thread instead of just waiting. However, there is an overhead of adding threads and additional work that will get accomplished. 2.2) CPU-bound But if your thread is CPU heavy, then a 1:1 correlation makes more sense, because adding more threads will only slow...

[Java - Synchronization] Queues

1) Blocking Queue A blocking queue is a queue that blocks when you attempt to: dequeue from it and the queue is empty, or  enqueue items to it and the queue is already full.  Example use case: if you want some action to be executed only after 100 clients log-in. 1.1) Implementation BlockingQueue<TYPE> queue = new  LinkedTransferQueue <>(); BlockingQueue<TYPE> queue = new  ArrayBlockingQueue <>(); 1.2) Methods put(..): Inserts the specified element at the tail of this queue, waiting for space to become available if the queue is full. take(..):  Retrieves and removes the head of this queue, waiting if necessary until an element becomes available. 2) Delay Queue An unbounded blocking queue of Delayed elements, in which an element can only be taken when its delay has expired.  3) Priority Queue An unbounded blocking queue that orders the elements based on the generic's compareTo method.  If generic i...

[Java - Synchronization] Latches

1) Countdown Latch A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes. A CountDownLatch is initialized with a given count. The await method is blocked until the current count reaches zero; we can reduce current count using the method,  countDown() . The count cannot be reset.  2) Cyclic Barrier Similar to countdown latch, but the count can reset. Resources https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html

[Java - Synchronization] ExecutorService and Futures

1) Overview While it is easy to create one or two threads and run them, it becomes a problem when your application requires creating 20 or 30 threads for running tasks concurrently. It won't be exaggerating to say that large multi-threaded applications will have hundreds, if not thousands of threads running simultaneously. So, it makes sense to separate thread creation and management from the rest of the application. ExecutorService is a framework provided by the JDK which simplifies the execution of tasks in asynchronous mode. Generally speaking, ExecutorService automatically provides a pool of threads and API for assigning tasks to it. Executors framework helps you with: Thread Creation : Provide methods for creating threads, more specifically a pool of threads, that your application can use to run tasks concurrently. Thread Management : Manage life cycle of the threads in the thread pool. You don’t need to worry about whether the threads in the thread pool ...