Skip to content
This repository has been archived by the owner on Dec 8, 2022. It is now read-only.

improved speed for fetching app information #597

Open
wants to merge 22 commits into
base: master
Choose a base branch
from

Conversation

twig
Copy link

@twig twig commented Mar 5, 2014

My main issue with Andlytics is that it takes up to 30-45s to request information for my 10+ apps as it does this one by one.

fetchAppInfosAndStatistics() now runs in parallel rather than one app at a time.
With this patch it takes me about 10-15s.

Sorry for the space removals, it's an Eclipse setting.

@willlunniss
Copy link
Contributor

How does this perform on a slow connection?

@@ -62,6 +62,9 @@

private ResponseHandler<String> responseHandler = HttpClientFactory.createResponseHandler();

// This is only used for synchronising fetchAppInfosAndStatistics()
private volatile int fetchAppInfoCounter;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use a java.util.concurrent.CountDownLatch instead of this plus the lock

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I didn't know that existed.

@willlunniss
Copy link
Contributor

Side point @nelenkov I know before we had a mess of throws 20 different exceptions, but maybe we should have at least a throws DevConsoleException (or whatever it is called) to the methods that throw them.

final Object lock = new Object();
fetchAppInfoCounter = 0;

for (final AppInfo app : apps) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could get silly for users with 20+, let alone those with 100+ apps (don't ask me why they have that many!), tbh even 10 threads in your case is quite high.

Probably need a ThreadPoolExecutor to keep the number down to a sensible amount (say 4/5 max, less on a slow connection).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could make the number of apps fetched at a time configurable, and manage it with a ThreadPoolExecutor.

That way users can control how many are updated at a time based on their own connection if it's a problem.

@willlunniss
Copy link
Contributor

I've made some comments. In summary, fetching everything one at a time as we currently do isn't great, but it cannot be solved by simply running everything at once as it doesn't scale.

It may be that we should ditch the concept of fetching all all info at once (except in the background syncs). And just update a few apps at once, this needs some thinking about.

@willlunniss
Copy link
Contributor

Oh and finally, any pull requests should be made against the dev branch.

@twig
Copy link
Author

twig commented Mar 5, 2014

How does this perform on a slow connection?

Actually, that's the reason why I implemented it. I spend lots of time waiting for the whole thing to update because of my poor 2G connection (in Australia...).

It performs quite well on a slow connection because it's only a small amount of data and the majority of the time I'm just waiting for data to be returned.

It may be that we should ditch the concept of fetching all all info at once (except in the background syncs). And just update a few apps at once, this needs some thinking about.

Hmm, I think your idea about a ThreadPoolExecutor will work better than breaking up the fetches into different intervals of the day.

My take is that a user would check the stats for all their apps once or twice a day for an overview of what's happening. Updating it at different times would be somewhat confusing and unecessarily complicate things.

Oh and finally, any pull requests should be made against the dev branch.

Sorry about that. Is there a way to change it or do I have to create another pull request?

Thanks for taking the time to make some comments (and provide advice!). I'll fix some of those up now.

- wrapped code inside of a try/finally block to prevent errors holding locks forever
@nelenkov
Copy link
Contributor

nelenkov commented Mar 6, 2014

Before going further with this, the app should be profiled to see where it takes the most time. If have proof that it's network, then you might try to optimize it. With most mobile connections the problem is latency -- it takes a long time to reach the server, getting data after that is usually more or less OK. So sending multiple requests in parallel might improve that a bit, but the number should be limited. Also, multithreading is hard :) Probably better to use Android tools (Handlers) to synchronize results.
Again, profile first to figure out where it takes time. There is a way to have HttpClient dump debug logs, search for it on SO, etc.

As for fetching everything at once, getting details only after select a particular app might help people with lots of app, so it's worth looking into. I'd like the mode to be selectable though, as I actually usually refresh manually and have background sync turned off. Maybe I should give it try though :)

@nelenkov
Copy link
Contributor

nelenkov commented Mar 6, 2014

Side point @nelenkov I know before we had a mess of throws 20 different exceptions,
but maybe we should have at least a throws DevConsoleException (or whatever it is called)
to the methods that throw them.

To enforce this we need to make all exceptions checked again, not sure if it's worth it. When running in a different thread, you generally need to catch all exceptions anyway, so it wont' help much here. Say you catch DevConsoleException, but not Exception, you'll still have a problem when something else goes wrong.

@twig
Copy link
Author

twig commented Mar 6, 2014

Before going further with this, the app should be profiled to see where it takes the most time. If have proof that it's network, then you might try to optimize it. With most mobile connections the problem is latency

I've tested this on both mobile connection and WiFi at work/home. There is a definite improvement in update times when doing it in parallel.

Also, multithreading is hard :) Probably better to use Android tools (Handlers) to synchronize results.

I understand your caution because this is my first commit towards the project and the patch affects core functionality. I am only working on this because it is a pain for me to wait up to a minute to fetch the updates one by one.

I've already switched it to use a CountDownLatch and put the unlock in a "finally" block (which is working nicely).

As for fetching everything at once, getting details only after select a particular app might help people with lots of app, so it's worth looking into. I'd like the mode to be selectable though

As for someone with lots of apps, why would it be helpful to update only the apps they click into? I could definitely make this a user-selectable option though. One option keeps fetches it one-by-one as it currently does. The second option allows the app to make multiple (or all) requests at once.

I actually usually refresh manually and have background sync turned off. Maybe I should give it try though :)

I also have background sync off and refresh manually, but I use Andlytics to see how my all apps are going once or twice a day. It would be bothersome to click onto each of my apps to update the stats.

@nelenkov
Copy link
Contributor

nelenkov commented Mar 6, 2014

By 'proof' I mean actual logs with actual timings, so we can see connecting took say 100 ms, fetching took 50 ms, parsing took 20ms, etc. As for threading, if you use Android messages you mostly don't need to bother with synchronization, as Handlers guarantee that everything is delivered to the same thread.

@twig
Copy link
Author

twig commented Mar 6, 2014

Hmm, how would you go about getting those logs? Or would Log.debug() calls be sufficient?

I'll submit the new code with the CountDownLatch fix. Personally I think it's simple enough to understand as the Handler code looks unnecessarily complicated (but I'll wait for the code review)

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

Successfully merging this pull request may close these issues.

3 participants