Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecate SendChannel.isFull and ReceiveChannel.isEmpty properties #1053

Closed
elizarov opened this issue Mar 20, 2019 · 7 comments
Closed

Deprecate SendChannel.isFull and ReceiveChannel.isEmpty properties #1053

elizarov opened this issue Mar 20, 2019 · 7 comments
Assignees

Comments

@elizarov
Copy link
Contributor

elizarov commented Mar 20, 2019

We are working on a better, faster algorithms for channel implementation and isFull and isEmpty experimental properties are hard to support there. Since we were not able to find any compelling use-cases to support those properties, we are removing them in advance (in upcoming release).

@Tolriq
Copy link

Tolriq commented Mar 20, 2019

I am currently using isFull for one simple case.
Testing if an actor without buffer is currently doing something or not, what would be the proper way to do that check?

@qwwdfsad
Copy link
Collaborator

qwwdfsad commented Mar 20, 2019

@Tolriq the proper solution is not to do it. Could you please elaborate on why you have to do that?

Channel is an implementation detail of how actor processes queued messages, not something that is exposed to the public. This is actually one of the reasons why current actors are obsolete and new ones (#87) will hide the channel as an implementation detail in the future.

The answer to the question "how to do it anyway when isFull is deprecated" depends on how exactly are you using this API. But the general approach is to use a domain-specific API that you can tune whenever you need.
Something (very trivial and verbose, just to show the general idea) like this:

class MyActor(val channel, val isActive)

createActor(): MyActor {
    val isActiveIndicator = AtomicBoolean()
    val channel = actor {
        // Operate on isActiveIndicator here
    }

  return MyActor(channel, isActiveIndicator)
}

@Tolriq
Copy link

Tolriq commented Mar 20, 2019

The need is not a "real" need, but an easy way to workaround an Android 8 issue with foreground services.

My actor is really simple actually

    internal val actor = actor<Unit> {
        consumeEach {
            startDownloads()
        }
    }

Due to racy conditions in Android 8 I have a case where I just check if the actor is running or not to call one more stopForeground in case the previous stopForeground was not working due to the startForeground not processed fast enough by the OS. (Love Android ;))
(With a simple if (!actor.isFull) { stopForeground(true) } )

I suppose I can just do the following to achieve the same result, but was hoping for something native without AtomicBoolean.

val running = AtomicBoolean(false)

    internal val actor = actor<Unit> {
        consumeEach {
            running.set(true)
            startDownloads()
            running.set(false)
        }
    }

@thewmo
Copy link

thewmo commented Apr 1, 2019

I have a use case, though I could imagine workarounds. I'm using (rendezvous) channels in a "fan-out" mode to distribute tasks to a variably-sized pool of actors (little-a, I'm not using the built-in actor abstraction).

Each actor is doing something like:

suspend fun run(inputChannel: Channel<Task>) {
    for (message in inputChannel) {
        // expensive-ish suspending processing here
    }
}

the code sending tasks is using isFull as a hint to add another actor to the party (subject to a max omitted for clarity):

if (taskChannel.isFull) {
    launch {
        MyActor().run(taskChannel)
    }
}
taskChannel.send(task)

I'm open to suggestions and alternatives. Simply launching a coro for each task would be an option if there were a way to constrain the number simultaneously active (to bound resource use) with queueing semantics when the bound is hit. If it's not obvious, this is a server-side use case.

ndkoval added a commit that referenced this issue Apr 4, 2019
…iveChannel.isEmpty` properties

See "Deprecate SendChannel.isFull and ReceiveChannel.isEmpty properties #1053"
ndkoval added a commit that referenced this issue Apr 4, 2019
…iveChannel.isEmpty` properties

See "Deprecate SendChannel.isFull and ReceiveChannel.isEmpty properties #1053"
@tprochazka
Copy link

I think that possibility to monitor the buffer remaining size is very useful for performance tuning when you need to found a problematic place in the processing chain for example.

I'm currently using isFull also for logging purposes.
I agree that makes sense to have a faster implementation, if this information is not important.
But would be great to have the possibility to provide my own buffer implementation in the case when it is important.

@tprochazka
Copy link

It is weird that isFull is actually really deprecated, but isEmpty is just marked as experimental.
But is there any change that even when this method will be removed from Channel directly will be still possible to use it by providing an alternative implementation of bugger? Like

val buffer = SomeChannelBuffer()
val channel = Channel(buffer)
buffer.isEmpty

In my app I'm using isEmpty often, for example, to do some cleaning operation at the moment when the data processing pipeline is not too busy.

@qwwdfsad
Copy link
Collaborator

@tprochazka isEmpty has all the chances to stay forever. We just haven't yet decided on its general contract (linearizability, mostly)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants