For example, for the following code:
OpenOutputWindow()
Sleep(2)
The output window only opens AFTER sleeping for 2 seconds. Why does this happen and how does one work around it? Do I need multiple threads?
Yes, your assumption is correct. UI updates of the software are generally performed on the "main thread" of the application. A script is, by default, also run on the main-thread and hence blocks those updates until some CPU cycles are made available for this.
Sometimes this can be achieved by calling dedicated Update commands (such as UpdateImage() or ShowImage() etc.) but this does not work for the text-output in the output window.
If the script is run on a separate thread, then you don't see this.
You can put a script into a separate thread like this (old method):
// $BACKGROUND$
OpenOutputWindow()
ClearResults()
Result("\nbefore sleep")
Sleep(2)
Result("\nafter sleep")
Note that the first line needs to be exactly like this, including the space and capitalization. It also needs to be the first line.
or you can do it like that (new, object oriented way):
class CMyClass
{
void MyMethod(object self)
{
OpenOutputWindow()
ClearResults()
Result("\nbefore sleep")
Sleep(2)
Result("\nafter sleep")
}
}
StartThread( Alloc(CMyClass), "MyMethod" )
Related
I have a bunch of network requests I want to conduct in parallel.
The following pseudo code should give a good idea of what I'm doing right now:
runBlocking {
buildList {
withContext(tracer.asContextElement()) {
items.forEach { item ->
add(
async {
// a few IO intensive operations (i.e. network requests)
}
)
}
}
}.awaitAll()
}
I have tracing tools set up and locally this seems to do the job. In my production infrastructure however the async tasks execute sequentially, i.e. the second one starts immediately after the first one finishes.
I have also tried using withContext(Dispatchers.IO.plus(tracer.asContextElement())) but I observe no difference.
The only thing I can say is that my development machine has multiple CPU cores, and my production machine will normally have 1. Regardless, due to the IO heavy nature of these processes I doubt this is the problem. I can't really explain what is causing this, but my gut feeling is that I'm fundamentally not understanding something about how Coroutines work in Kotlin.
As to the nature of the network request in question, I'm using a third party SDK that asynchronously executes the request, and seems to use ForkJoinPool.commonPool() under the hood as an executor.
If you don't switch dispatchers here, all those coroutines will run in the same thread - the one blocked by runBlocking. If the computation inside each coroutine is blocking, they will block the only thread one by one without any way to parallelize. This would explain what you're seeing (although it's strange that you don't reproduce locally).
I have also tried using withContext(Dispatchers.IO.plus(tracer.asContextElement())) but I observe no difference.
Your fix should work, unless the IO you're performing is actually managing threads itself and also confining the execution to a single thread no matter where it's called from. Maybe you should look into the actual IO then.
EDIT: you mentioned that you perform the IO operations via a third party SDK that uses the common ForkJoinPool - this one is backed by a single thread on a single-CPU machine, so this explains why the calls aren't parallelized in your single-CPU production machine. The only options to fix that would be:
check whether the SDK you're using allows to customize the backing pool of threads
customize the size of the ForkJoinPool using the JVM property java.util.concurrent.ForkJoinPool.common.parallelism
use another SDK :)
You still need to customize the dispatcher in addition to that if you're calling the library in a blocking way, but not if you're converting their async tasks into suspensions using Future.await() or similar.
Now, a few other things to note in this code:
you don't need buildList { .. }, you can just use map { thing } instead of forEach { add(thing) } and you'll get the resulting list as a return value (it also works across withContext, because it returns the lambda result)
withContext actually waits for all child coroutines to finish, so awaitAll() is misplaced here (it should rather be inside withContext)
actually, you probably don't need withContext at all, you can pass the custom context directly to runBlocking, unless you have other things in runBlocking that you don't want to run in this context
(optional) if the IO computations don't return results, you don't need awaitAll at all, and you could just use launch instead.
Assuming you do need the result, so ignoring the last point, your current code (with dispatcher fix) could be rewritten to:
val results = runBlocking(Dispatchers.IO + tracer.asContextElement()) {
items.map { item ->
async {
performIO(item)
}
}.awaitAll()
}
Otherwise:
runBlocking(Dispatchers.IO + tracer.asContextElement()) {
items.map { item ->
launch {
performIO(item)
}
}
}
I am using Kotlin together with Arrow-Kt libraries.
I am launching on a specific scope some coroutines that make use of Arrow-kt's Schedule.
At a certain time, I want to be able to cancel all those coroutines that were launched on that scope, but after I cancel the scope basically nothing changes and whatever was running on the Schedule, continues to run, which is not what I wanted.
I already tried to place some yield() calls to force the coroutines to be cancellable, but the behavior didn't change.
Here is the code:
Main function doing the launches:
private val ballFetchingScope= CoroutineScope(CoroutineName("ball-fetching"))
fun fetchBalls(periodicity: Periodicity) {
val balls = stockRepository.getAllBalls() //basically a list of different balls
balls.forEach {
ballFetchingScope.launch(Dispatchers.IO) { ballFetcher.startFetching(it, periodicity) }
}
}
startFetching function, using Arrow-kt's schedule:
suspend fun startFetching(ball: Ball, periodicity: Periodicity) {
Schedule.forever<Unit>()
.and(Schedule.spaced(periodicity))
.repeat {
yield()
//ball fetching logic here
}
}
Expected behavior:
When calling ballFetchingScope.cancel() all coroutines are cancelled and all fetching stops.
Ideally not even needing to wait until it reaches the yield() call, if it is waiting for the next run to happen, I would like for it to cancel and not even start a new run of the repeat block.
What is actually happening:
Fetching continues to happen normally.
It's a bit hard to say here what is going on.
It's very strange that this is not working for you, since Schedule relies on KotlinX kotlin.coroutines.delay to execute the Schedule.spaced. So it should get cancelled while waiting for the next run.
It also checks coroutineContext.ensureActive() before running the function passed to repeat so it also automatically check in the place where you now manually placed yield.
Which version of Arrow are you using? And could you share a fully reproducible example?
I am answering my own post just to make sure you are not making the same dumb mistake I was making.
Everything was working as supposed, the issue was on my side.
I had two different instances of the class containing the ballFetchingScope
This means that I was calling the ballFetchingScope.cancel() on the scope for one of those instances while the Coroutines were running on the scope in the other instance.
Botom-line: Make sure you are not using multiple instances when you think you have only one.
I'm writing a scheduler. It has a single form frmMain, which shows jobs that are currently running, and a history of job steps that have run. It has an object of class Scheduler that manages running new jobs. Scheduler keeps a collection class, List which contains objects of class RunningJob. RunningJob executes each step in turn through a series of sub-classes.
When a job is started, the Scheduler creates a new BackgroundWorker with the DoWork, ProgressChanged and RunWorkerCompleted methods setup with handlers that point back into the instance of RunningJob.
Each time a job/step starts/ends, one of these handers in RunningJob raises an appropriate event into Scheduler and Scheduler raises an appropriate event into frmMain. i.e.:
frmMain (1 instance) <---- Scheduler (1 instance) <---- RunningJob.WorkerProgressChanged (many instances)
The RunningJob executes correctly, but the reporting going up to the interface is not working correctly. Also any logging to files I do is suspect (I'm using a single function: LogInfo to do this). I have a number of questions:
When I use InvokeRequired() and Invoke() within frmMain, do I have to do this with every single control I want to update (there are several). Can I just check InvokeRequired() on one control and use Invoke on all of them based on that result.
Why bother checking InvokeRequired() at all and just use Invoke() every single time? It will make for simpler code.
There is only one instance of Scheduler and I am raising events to get execution back into it from each Job. I think this is part of the problem. How is multithreading handled doing this? Is there some sort of InvokeRequired/Invoke check I can do on the events before raising them? Can I raise events at all in this situation? I like events, rather than calling methods on the owner class, because it improves encapsulation. What is best practice here?
In general, if I'm calling a piece of code from many different threads, not necessarily to update a form, but just to perform some function (e.g. add a line of text to a file for logging purposes), how do I block one thread until the other has completed?
How can i restrict my program to run only instance? Currently i'm running my program as daemon(starts and stops automatically), and when user clicks and tries to launch again(which is not a valid usecase), process gets launched in user context and i would like to avoid this for many reasons.
How can i achieve this?
As of now i'm getting list of processes and doing some checks and exiting at the begining itself but this method is not clean, though it solves my problem.
can someone give me a better solution?
And i'm using ps to get process list, is there any reliable API to get this done?
Use a named semaphore with count of 1. On startup, check if this semaphore is taken. If it is, quit. Otherwise, take it.
Proof of concept code: (put somewhere near application entry point)
#include <semaphore.h>
...
if (sem_open(<UUID string for my app>, O_CREAT, 600, 1) == SEM_FAILED) {
exit(0);
}
From the sem_open documentation,
The returned semaphore descriptor is available to the calling process until it is closed with sem_close(), or until the caller exits or execs.
Inside ClassA:
-(void)authenticateUser
{
authenticate_Obj = [classB_Obj authenticateMobileUser];
}
Inside ClassB:
-(AuthenticateObj*)authenticateMobileUser
{
[mobile_Obj AuthenticateMobileServer:self action:#selector(Handler:)];
return authenticate_G_Obj;
}
-(void)Handler:(id)value
{
authenticate_G_Obj = (AuthenticateObj*)value;
}
Now once the authenticateMobileUser method of classB returns the controll back to ClassA, we will get the Object authenticate_Obj initiated.
My problem is , when i run the project the authenticate_Obj is NULL... actually when it enters the handler method , the Object is initiallized. but the controlled is returned back to ClassA, without entering into Handler method. I guess this is the problem of Asynchronous execution.
How to make it enter into handler method and then only return the controll to ClassA??
Plz help me..
Thank You.
It sounds like what you think you want to do is to block execution until authentication completes. This might be possible if AuthenticateMobileServer spawns a background thread to work in -- you'd use a synchronisation object such as NSLock -- but it's really a Bad Idea. Why have a background thread at all if you're going to block anyway? And thread synchronisation is notoriously tricky and prone to errors if you don't know what you're doing, which (let's face it) you don't.
Instead, you probably should accept that there will be a period of uncertainty while the authentication takes place, during which your app should keep processing in some intermediate state, and then use a callback to notify you when the authentication is complete and you can then go on with whatever it is you need to do with the authenticated user.
There are a bunch of ways you could do this, and there's not enough detail in the question to say exactly which would be best. But you already seem to be using something very similar within ClassB, so I'd say do the same from ClassA:
Inside ClassA:
-(void)authenticateUser
{
authenticate_Obj = nil;
[classB_Obj authenticateMobileUserAndNotify:self action:#selector(authenticatedObject:)];
// returns more or less immediately, not yet authenticated
}
-(void)authenticatedObject:(YourAuthObjectClass*) authObj
{
authenticate_Obj = authObj;
// do post-authentication stuff here
}
Inside ClassB:
-(void)authenticateMobileUserAndNotify:(id)target action:(SEL)sel
{
// I'm making these ivars for simplicity, there might be other considerations though
callbackTarget = target;
callbackSelector = sel;
[mobile_Obj AuthenticateMobileServer:self action:#selector(Handler:)];
}
-(void)Handler:(id)value
{
authenticate_G_Obj = (AuthenticateObj*)value;
[callbackTarget performSelectorOnMainThread:callbackSelector withObject:authenticate_G_Obj waitUntilDone:NO];
}
Obviously this is just a sketch and not intended to be used as is. And you'll need to consider what goes on in your app while in the waiting state, with authentication in progress but authenticate_Obj still nil. But hopefully you get the idea.
I think you are saying that AuthenticateMobileServer:action: is asynchronous and you want to block until it's finished so you can get the return value. Unfortunately, we can't really tell you without knowing how it works. The main question is does it run the Handler action on the main thread or a secondary thread.
If it runs the action on the main thread, the best strategy is to return immediately from authenticateMobileUser without waiting for the authentication object and disable the UI elements that depend on being authenticated. Then later when you get the authentication object, you should re-enable the UI elements.
If it runs the action on a background thread, the easiest thing is to set up another method similar to Handler (by the way, the naming convention for methods and variables is to start with lower case), which you then invoke from Handler with performSelectorOnMainThread:waitUntilDone:. You can then use the same strategy as outlined above.
Both answers of JeremyP and walkytalky are correct and go at the heart of creating a respondsive UI. The rule of thumb:
If you doing potentially blocking operations such as networking on the main thread, you will get in trouble.
There are at least two reasons:
you are blocking the run loop so it cannot process user events anymore. This will result in a spinning beachball on the mac and a unresponsive UI on both mac and iOS.
If you are on iOS, there is a watchdog going around and checking if your UI is still responding to user events. If you are blocking the UI longer than I think 20s you will be terminated with the error code 0x8badf00d.
So to get this things done which maybe take some time you have to do it on the background thread. As the two answers of JeremyP and walkytalky point out often you get a callback. That is fine but there are in total three ways of messaging:
Delegation
Notifications
Kev-value-observing
All three can be and are used. There are subtle differences between them. One of the most important is that delegation is a 1:1 messaging whereas the other to are a 1:n messaging.
Now that said do not think that you have to use NSThread. Have a look at NSOperation and NSOperationQueue instead. They allow to encapsulate pieces of work in an operation and let them run on a queue in the background. Also if you are using these callbacks with the #selector(methodname:) syntax there is something new: blocks. Often there are equivalent methods which take a block instead of a selector to be executed as a callback.
To finish here is the golden rule:
You may update your model on the background thread, but NEVER update your UI on a background thread.
Check out the WWDC10 videos about these topics. There is a great 2-part talk about networking which explains the concepts in detail.