I have a go function which will do some logic after the Channel have received some logic.
My problem is I want the function to keep alive after it has done the logic. My thinking is
that I will add a endless while loop in the function. However, I am wondering whether this is
a good technique. My Code is as follows:
func process(channel chan string, sid string) {
inputSid := <-channel
// check if sid exist in process pool
if strings.EqualFold(sid, inputSid) {
fmt.Println("Got message", sid)
//the code that I added to make this function alive
for {}
} else {
channel <- sid
//the code that I added to make this function alive
for {}
}
}
For future reference:
A better way to keep alive a function is to use an empty select statement which will block a Go routine indefinitely. As opposed to an empty for statement, it does not consume CPU time doing so.
select { }
Just use the standard "Go way". You can range over a channel until it is closed:
for sid := range channel {
// do stuff
}
It will continue until the channel is closed. Adding a "wait loop" like that is asking for trouble.
Related
I'm scratching my head around properly cancelling coroutine job.
Test case is simple I have a class with two methods:
class CancellationTest {
private var job: Job? = null
private var scope = MainScope()
fun run() {
job?.cancel()
job = scope.launch { doWork() }
}
fun doWork() {
// gets data from some source and send it to BE
}
}
Method doWork has an api call that is suspending and respects cancellation.
In the above example after counting objects that were successfully sent to backend I can see many duplicates, meaning that cancel did not really cancel previous invocation.
However if I use snippet found on the internet
internal class WorkingCancellation<T> {
private val activeTask = AtomicReference<Deferred<T>?>(null)
suspend fun cancelPreviousThenRun(block: suspend () -> T): T {
activeTask.get()?.cancelAndJoin()
return coroutineScope {
val newTask = async(start = CoroutineStart.LAZY) {
block()
}
newTask.invokeOnCompletion {
activeTask.compareAndSet(newTask, null)
}
val result: T
while (true) {
if (!activeTask.compareAndSet(null, newTask)) {
activeTask.get()?.cancelAndJoin()
yield()
} else {
result = newTask.await()
break
}
}
result
}
}
}
It works properly, objects are not duplicated and sent properly to BE.
One last thing is that I'm calling run method in a for loop - but anyways I'm not quire sure I understand why job?.cancel does not do its job properly and WorkingCancellation is actually working
Short answer: cancellation only works out-of-the box if you call suspending library functions. Non-suspending code needs manual checks to make it cancellable.
Cancellation in Kotlin coroutines is cooperative, and requires the job being cancelled to check for cancellation and terminate whatever work it's doing. If the job doesn't check for cancellation, it can quite happily carry on running forever and never find out it has been cancelled.
Coroutines automatically check for cancellation when you call built-in suspending functions. If you look at the docs for commonly-used suspending functions like await() and yield(), you'll see that they always say "This suspending function is cancellable".
Your doWork isn't a suspend function, so it can't call any other suspending functions and consequently will never hit one of those automatic checks for cancellation. If you do want to cancel it, you will need to have it periodically check whether the job is still active, or change its implementation to use suspending functions. You can manually check for cancellation by calling ensureActive on the Job.
In addition to Sam's answer, consider this example that mocks a continuous transaction, lets say location updates to a server.
var pingInterval = System.currentTimeMillis()
job = launch {
while (true) {
if (System.currentTimeMillis() > pingInterval) {
Log.e("LocationJob", "Executing location updates... ")
pingInterval += 1000L
}
}
}
Continuously it will "ping" the server with location udpates, or like any other common use-cases, say this will continuously fetch something from it.
Then I have a function here that's being called by a button that cancels this job operation.
fun cancel() {
job.cancel()
Log.e("LocationJob", "Location updates done.")
}
When this function is called, the job is cancelled, however the operation keeps on going because nothing ensures the coroutine scope to stop working, all actions above will print
Ping server my location...
Ping server my location...
Ping server my location...
Ping server my location...
Location updates done.
Ping server my location...
Ping server my location...
Now if we insert ensureActive() inside the infinite loop
while (true) {
ensureActive()
if (System.currentTimeMillis() > pingInterval) {
Log.e("LocationJob", "Ping server my location... ")
pingInterval += 1000L
}
}
Cancelling the job will guarantee that the operation will stop. I tested using delay though and it guaranteed total cancellation when the job it is being called in is cancelled. Emplacing ensureActive(), and cancelling after 2 seconds, prints
Ping server my location...
Ping server my location...
Location updates done.
I am trying to get the size of this firebase collection size of documents, and for some reason in Kotlin, I can't seem to get this to work. I have declared a variable to be zero in an int function and I put it inside a for loop where it increments to the size of the range. Then when I return the value, it is zero. Here is the code I have provided, please help me as to why it is returning zero.
This is just what is being passed to the function
var postSize = 0
That is the global variable, now for below
val db = FirebaseFirestore.getInstance()
val first = db.collection("Post").orderBy("timestamp")
getPostSize(first)
This is the function
private fun getPostSize(first: Query){
first.get().addOnSuccessListener { documents ->
for(document in documents) {
Log.d(TAG, "${document.id} => ${document.data}")
getActualPostSize(postSize++)
}
}
return postSize
}
private fun getActualPostSize(sizeOfPost: Int): Int {
// The number does push to what I am expecting right here if I called a print statement
return sizeOfPost // However here it just returns it to be zero again. Why #tenffour04? Why?
}
It is my understanding, according to the other question that this was linked to, that I was suppose to do something like this.
This question has answers that explain how to approach getting results from asynchronous APIs, like you're trying to do.
Here is a more detailed explanation using your specific example since you were having trouble adapting the answer from there.
Suppose this is your original code you were trying to make work:
// In your "calling code" (inside onCreate() or some click listener):
val db = FirebaseFirestore.getInstance()
val first = db.collection("Post").orderBy("timestamp")
val postSize = getPostSize(first)
// do something with postSize
// Elsewhere in your class:
private fun getPostSize(first: Query): Int {
var postSize = 0
first.get().addOnSuccessListener { documents ->
for(document in documents) {
Log.d(TAG, "${document.id} => ${document.data}")
postSize++
}
}
return postSize
}
The reason this doesn't work is that the code inside your addOnSuccessListener is called some time in the future, after getPostSize() has already returned.
The reason asynchronous code is called in the future is because it takes a long time to do its action, but it's bad to wait for it on the calling thread because it will freeze your UI and make the whole phone unresponsive. So the time-consuming action is done in the background on another thread, which allows the calling code to continue doing what it's doing and finish immediately so it doesn't freeze the UI. When the time-consuming action is finally finished, only then is its callback/lambda code executed.
A simple retrieval from Firebase like this likely takes less than half a second, but this is still too much time to freeze the UI, because it would make the phone seem janky. Half a second in the future is still in the future compared to the code that is called underneath and outside the lambda.
For the sake of simplifying the below examples, let's simplify your original function to avoid using the for loop, since it was unnecessary:
private fun getPostSize(first: Query): Int {
var postSize = 0
first.get().addOnSuccessListener { documents ->
postSize = documents.count()
}
return postSize
}
The following are multiple distinct approaches for working with asynchronous code. You only have to pick one. You don't have to do all of them.
1. Make your function take a callback instead of returning a value.
Change you function into a higher order function. Since the function doesn't directly return the post size, it is a good convention to put "Async" in the function name. What this function does now is call the callback to pass it the value you wanted to retrieve. It will be called in the future when the listener has been called.
private fun getPostSizeAsync(first: Query, callback: (Int) -> Unit) {
first.get().addOnSuccessListener { documents ->
val postSize = documents.count()
callback(postSize)
}
}
Then to use your function in your "calling code", you must use the retrieved value inside the callback, which can be defined using a lambda:
// In your "calling code" (inside onCreate() or some click listener):
val db = FirebaseFirestore.getInstance()
val first = db.collection("Post").orderBy("timestamp")
getPostSizeAsync(first) { postSize ->
// do something with postSize inside the lambda here
}
// Don't try to do something with postSize after the lambda here. Code under
// here is called before the code inside the lambda because the lambda is called
// some time in the future.
2. Handle the response directly in the calling code.
You might have noticed in the above solution 1, you are really just creating an intermediate callback step, because you already have to deal with the callback lambda passed to addOnSuccessListener. You could eliminate the getPostSize function completely and just deal with callbacks at once place in your code. I wouldn't normally recommend this because it violates the DRY principle and the principle of avoiding dealing with multiple levels of abstraction in a single function. However, it may be better to start this way until you better grasp the concept of asynchronous code.
It would look like this:
// In your "calling code" (inside onCreate() or some click listener):
val db = FirebaseFirestore.getInstance()
val first = db.collection("Post").orderBy("timestamp")
first.get().addOnSuccessListener { documents ->
val postSize = documents.count()
// do something with postSize inside the lambda here
}
// Don't try to do something with postSize after the lambda here. Code under
// here is called before the code inside the lambda because the lambda is called
// some time in the future.
3. Put the result in a LiveData. Observe the LiveData separately.
You can create a LiveData that will update its observers about results when it gets them. This may not be a good fit for certain situations, because it would get really complicated if you had to turn observers on and off for your particular logic flow. I think it is probably a bad solution for your code because you might have different queries you want to pass to this function, so it wouldn't really make sense to have it keep publishing its results to the same LiveData, because the observers wouldn't know which query the latest postSize is related to.
But here is how it could be done.
private val postSizeLiveData = MutableLiveData<Int>()
// Function name changed "get" to "fetch" to reflect it doesn't return
// anything but simply initiates a fetch operation:
private fun fetchPostSize(query: Query) {
first.get().addOnSuccessListener { documents ->
postSize.value = documents.count()
}
}
// In your "calling code" (inside onCreate() or some click listener):
val db = FirebaseFirestore.getInstance()
val first = db.collection("Post").orderBy("timestamp")
fetchPostSize(first)
postSizeLiveData.observer(this) { postSize ->
// Do something with postSize inside this observer that will
// be called some time in the future.
}
// Don't try to do something with postSize after the lambda here. Code under
// here is called before the code inside the lambda because the lambda is called
// some time in the future.
4. Use a suspend function and coroutine.
Coroutines allow you to write synchronous code without blocking the calling thread. After you learn to use coroutines, they lead to simpler code because there's less nesting of asynchronous callback lambdas. If you look at option 1, it will become very complicated if you need to call more than one asynchronous function in a row to get the results you want, for example if you needed to use postSize to decide what to retrieve from Firebase next. You would have to call another callback-based higher-order function inside the lambda of your first higher-order function call, nesting the future code inside other future code. (This is nicknamed "callback hell".) To write a synchronous coroutine, you launch a coroutine from lifecycleScope (or viewLifecycleOwner.lifecycleScope in a Fragment or viewModelScope in a ViewModel). You can convert your getter function into a suspend function to allow it to be used synchronously without a callback when called from a coroutine. Firebase provides an await() suspend function that can be used to wait for the result synchronously if you're in a coroutine. (Note that more properly, you should use try/catch when you call await() because it's possible Firebase fails to retrieve the documents. But I skipped that for simplicity since you weren't bothering to handle the possible failure with an error listener in your original code.)
private suspend fun getPostSize(first: Query): Int {
return first.get().await().count()
}
// In your "calling code" (inside onCreate() or some click listener):
lifecycleScope.launch {
val db = FirebaseFirestore.getInstance()
val first = db.collection("Post").orderBy("timestamp")
val postSize = getPostSize(first)
// do something with postSize
}
// Code under here will run before the coroutine finishes so
// typically, you launch coroutines and do all your work inside them.
Coroutines are the common way to do this in Kotlin, but they are a complex topic to learn for a newcomer. I recommend you start with one of the first two solutions until you are much more comfortable with Kotlin and higher order functions.
I am attempting to get the address out of the callback function. I have been reading the documentation for CallBacks and some posts but still don't get why this is not working, as at the moment of returning the 'address' variable the callback has already finished.
private fun getAddressForCoordinates(geoCoordinates: GeoCoordinates):String {
address = "unchanged"
val maxItems = 1
val reverseGeocodingOptions = SearchOptions(LanguageCode.EN_GB, maxItems)
searchEngine.search(geoCoordinates, reverseGeocodingOptions, addressSearchCallback)
return address
}
private val addressSearchCallback =
SearchCallback { searchError, list ->
if (searchError != null) {
//showDialog("Reverse geocoding", "Error: $searchError")
Toast.makeText(context, "Error: $searchError", Toast.LENGTH_LONG).show()
return#SearchCallback
}
Toast.makeText(
context,
"Reverse geocoded address:" + list!![0].address.addressText,
Toast.LENGTH_LONG
).show()
address = list[0].address.addressText
}
From your code and comment I assume you are not familiar with the concept of asynchronous execution. That concept was well described here. I'll quote the main point:
When you execute something synchronously, you wait for it to finish
before moving on to another task. When you execute something
asynchronously, you can move on to another task before it finishes.
The fact that search() requires providing a callback and it doesn't simply return search results, is a good indication that it is most probably asynchronous. Invoking it is like saying: "Search for the data in the background and let me know when you have it. This is my email address - please send me my results there". Where email address is your callback. Invoking search() method does not block execution of your code, it does not wait for results - it only schedules searching and returns almost immediately.
Asynchronous processing is usually more tricky than a regular, synchronous code, but in many cases it is more efficient. In your case you can either try to "convert" original async API of the library to sync API that your code expects - but this is not recommended approach. Or you can redesign your code, so it will work asynchronously. For example, instead of doing this:
fun yourMethodThatNeedsAddress() {
val address = getAddressForCoordinates()
doSomethingWithAddress(address)
}
You need to do this:
fun yourMethodThatNeedsAddress() {
scheduleGetAddressForCoordinates() // renamed getAddressForCoordinates()
}
fun addressSearchCallback() {
...
doSomethingWithAddress(address)
}
So, whatever you planned to do with the acquired address, you can't do this straight after you started searching. You need to wait for a callback and then continue with processing of your address from there.
The SearchEngine from the 4.x HERE SDK needs an online connection as it is fetching results from a remote backend. This may take a few milliseconds, depending on your network connection. So, whenever you perform a search request, you need to wait until the callback is called:
searchEngine.search(geoCoordinates, reverseGeocodingOptions, addressSearchCallback)
When you call this, you pass addressSearchCallback as parameter. The implementation for addressSearchCallback can look like in your example. It will be called whenever the operation has finished. If the device is offline, then an error will be shown.
Note that the search() method is not returning any results immediately. These are passed to the callback, which happens asynchronously on a background thread. Thus, your application can continue to work without blocking any UI.
Once results are retrieved, the callback will be executed by the HERE SDK on the main thread.
So, if your code needs to do something with the address result, you have to do it inside the onSearchCompleted() method defined by the SearchCallback. If you write it in plain Java without lambda notation, it is more visible: You create a new SearchCallback object and pass it as parameter to the SearchEngine. The SearchEngine stores the object and executes the object's onSearchCompleted() whenever it thinks it's the right time:
private SearchCallback addressSearchCallback = new SearchCallback() {
#Override
public void onSearchCompleted(#Nullable SearchError searchError, #Nullable List<Place> list) {
if (searchError != null) {
showDialog("Reverse geocoding", "Error: " + searchError.toString());
return;
}
// If error is null, list is guaranteed to be not empty.
showDialog("Reverse geocoded address:", list.get(0).getAddress().addressText);
// Here is the place to do something more useful with the Address object ...!
}
};
I took this from this GitHub code snippet. Note that there is also an OfflineSearchEngine, that works without an internet connection, but for some reason it follows the same pattern and executes the task asynchronously.
private void getAddressForCoordinates(GeoCoordinates geoCoordinates) {
int maxItems = 1;
SearchOptions reverseGeocodingOptions = new SearchOptions(LanguageCode.EN_GB, maxItems);
searchEngine.search(geoCoordinates, reverseGeocodingOptions, new SearchCallback() {
#Override
public void onSearchCompleted(#Nullable SearchError searchError, #Nullable List<Place> list) {
if (searchError != null) {
showDialog("Reverse geocoding", "Error: " + searchError.toString());
return;
}
// If error is null, list is guaranteed to be not empty.
showDialog("Reverse geocoded address:", list.get(0).getAddress().addressText);
}
});
}
SearchEngine, a SearchOptions instance needs to be provided to set the desired LanguageCode. It determines the language of the resulting address. Then we can make a call to the engine's search()-method to search online for the address of the passed coordinates. In case of errors, such as when the device is offline, SearchError holds the error cause.
The reverse geocoding response contains either an error or a result: SearchError and the result list can never be null at the same time - or non-null at the same time.
The Address object contained inside each Place instance is a data class that contains multiple String fields describing the address of the raw location, such as country, city, street name, and many more. Consult the API Reference for more details. If you are only interested in receiving a readable address representation, you can access addressText, as shown in the above example. This is a String containing the most relevant address details, including the place's title.
Please refer to following link for detailed documentation on search() function and parameters associated with it.
https://developer.here.com/documentation/android-sdk-explore/4.4.0.2/dev_guide/topics/search.html
I would like to consume some stream-data using Kotlin actors
I was thinking to put my consumer inside an actor, while it polls in an infinite loop while(true). Then, when I decide, I send a message to stop the consumer.
Currently I have this:
while(true) {
for (message in channel){ <--- blocked in here, waiting
when(message) {
is MessageStop -> consumer.close()
else -> {}
}
}
consumer.poll()
}
The problem
The problem with this is that it only runs when I send a message to the actor, so my consumer is not polling the rest of the time because channel is blocking waiting to receive the next message
Is there any alternative?, someone with the same issue?, or something similar to actors but not blocked by channel in Kotlin?
Since the channel is just a Channel (https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-channel/index.html) you can first check if the channel is empty and if so start your polling. Otherwise handle the messages.
E.g.
while(true) {
while (channel.isNotEmpty()) {
val message = channel.receive()
when(message) {
is MessageStop -> consumer.close()
else -> {}
}
}
consumer.poll()
}
In the end I used AKKA with Kotlin, I'm finding much easier this way
You should use postDelayed(), for example:
final Runnable r = new Runnable() {
public void run() {
// your code here
handler.postDelayed(this, 1000)
}
}
You can change 1000 with the the millisecond delay you want. Also I highly recommend to put your code inside a thread (if you are not already have) to prevent ANR (App Not Responding)
The function send() in the following example calls itself recursively:
internal inner class RouteSender(
val features: List<Feature>,
val exchange: GrpcUniExchange<Point, RouteSummary>
) {
var result: AsyncResult<RouteSummary>? = null // Set in stub for recordRoute.
fun send(numPoints: Int) {
result?.let {
// RPC completed or err'd before sending completed.
// Sending further requests won't error, but they will be thrown away.
return
}
val index = random.nextInt(features.size)
val point = features[index].location
println("Visiting point ${RouteGuideUtil.getLatitude(point)}, " +
"${RouteGuideUtil.getLongitude(point)}")
exchange.write(point)
if (numPoints > 0) {
vertx.setTimer(random.nextInt(1000) + 500L) { _ ->
send(numPoints - 1)
}
} else {
exchange.end()
}
}
}
It can be re-written so that the last operation performed is the recursive call to itself:
...
if (numPoints <= 0) {
exchange.end()
} else {
vertx.setTimer(random.nextInt(1000) + 500L) { _ ->
send(numPoints - 1)
}
}
...
Yet, if I mark it as a tailrec function, I get a warning that the recursive call is not a tail call. This doesn't stop compilation of the successful running of the program. However, why is this not a tail call?
The documentation says:
To be eligible for the tailrec modifier, a function must call itself
as the last operation it performs. You cannot use tail recursion when
there is more code after the recursive call, and you cannot use it
within try/catch/finally blocks.
This is not within a try/catch/finally block and there is no more code after the recursive call. What is it that means this code block is ineligible for tail recursion optimisation?
I'll take a stab at answering my own question, in that it has no return value. Based on this discussion, that's about all I can think of. Thoughts?
Although your method appears to contain a call to itself, it's not actually a recursive method at all.
The call to send appears inside a closure. That means that it's not invoked immediately. It will only be invoked when the closure itself is invoked. In your case, that's done by a timer. It will take place outside of the current call stack, and probably even outside of the current thread.
In any case, the last call is the call to vertx.setTimer.
Kotlin allows inline closure functions which it uses for a number of it's own library functions, such as forEach. The tailrec might work if it's called from an inline closure, after all return from an inline closure returns from the outer function.
However, as noted above, this is a timer callback function, so it can by definition not be an inline call, and not be tail recursive.