-
Notifications
You must be signed in to change notification settings - Fork 9
Threads
Java and Kotlin allow you to easily spawn multiple threads in your program, allowing you to execute separate pieces of code in parallel. Either by manually creating each thread and setting it going, or automatically in something like a parallel for loop where each iteration of the loop is run on separate threads in parallel.
Python doesn't normally let you do this. It has some ability to schedule code to run on a single thread so that it looks like it's multi-threading, but in reality it is only using one thread and thus can only be using one processor core. However, since you are using JISA
you must be using Jython (or something equivalent), which gives you access to Java threads. This is, generally, why Jython exists: to take advantage of the technical superiority of Java from within Python.
The simplest for of threading is by creating Thread
objects. These are very simple. You create them by giving them a Runnable
(see "Functions as Objects") to run and then start them.
For example:
Java
Thread myThread = new Thread(() -> {
int total = 1;
for (int i = 1; i <= 100; i++) {
total *= i;
}
System.out.printf("100! = %d\n", total);
});
myThread.start();
Kotlin
val myThread = Thread {
var total = 1
for (i in 1..100) {
total *= i
}
println("100! = $total")
}
myThread.start()
Jython
from java.lang import Thread
def calcFactorial():
total = 1
for i in range(1, 101, 1):
total *= i
print("100! = %d" % total)
myThread = Thread(calcFactorial)
myThread.start()
When we call start()
on this thread it will start calculating 100 factorial and then print out the result. When it's done the thread shuts down. Anything we write after myThread.start()
will run immediately since the code in our Thread
object is running on a separate thread.
To illustrate this, we can set two threads off simultaneously:
Thread thread1 = new Thread(() -> {
while (true) {
System.out.println("This is from thread 1!");
Util.sleep(500);
}
});
Thread thread2 = new Thread(() -> {
while (true) {
System.out.println("This is from thread 2!");
Util.sleep(430);
}
});
thread1.start();
thread2.start();
The result will be both the lines "This is from thread 1!" and "This is from thread 2!" being output at intervals of 500 ms and 430 ms respectively.
If you have a Collection
of some sort, for example a List
such as an ArrayList
or LinkedList
, then you can iterate over it in parallel by use of the parallelStream
feature.
List<Double> myList = new LinkedList<>();
myList.add(1.0); // etc
// This will perform a for-each loop but on parallel streams (if possible)
myList.parallelStream().forEach((v) -> {
System.out.println(v);
});
This will perform the action defined in the lambda function for each element in myList
, automatically creating new threads to carry it out (the number based on how many processor cores you have). This will block until all these automatically created threads have finished their work. As a result of each element being processed in parallel, it might not necessarily be processed in the order that the items are listed in. It will come down to which thread gets there first. For example, trying this with a list of [1.0, 2.0, 3.0, 4.0, 5.0]
processed them in the order [3.0, 1.0, 2.0, 4.0, 5.0]
. If run again, it would likely be in a different order again.
This functionality is available in both Kotlin and Jython due to their ability to use Java's Collection
classes:
Kotlin
list.parallelStream().forEach { println(it) }
Python
list.parallelStream().forEach(lambda v: print(v))
To help with some synchronisation, Java provides the Semaphore
class. These objects act as co-ordinators, holding back code until it is ready to be run. They work based on a system of "permits". Each object has a number of permits it can hand out at any given time. If a thread attempts to acquire one from a Semaphore
but it has none to give, the thread will block until it has one.
Java lets you schedule events to happen using Timer
and TimerTask
objects. A Timer
object is what does the scheduling, deciding when to run a task whereas a TimerTask
is the task to run itself. For example:
TimerTask task = new TimerTask() {
void run() {
System.out.println("The task has been run!");
}
};
Timer timer = new Timer();
// Schedule task to run 5000 ms from now
timer.schedule(task, 5000);
the output:
* Program Starts *
* Blank Console for 5 seconds *
The task has been run!
* Program Terminates *
- Getting Started
- Object Orientation
- Choosing a Language
- Using JISA in Java
- Using JISA in Python
- Using JISA in Kotlin
- Exceptions
- Functions as Objects
- Instrument Basics
- SMUs
- Thermometers (and old TCs)
- PID and Temperature Controllers
- Lock-Ins
- Power Supplies
- Pre-Amplifiers
- Writing New Drivers