Archived

This forum has been archived. Please start a new discussion on GitHub.

Beginner's questions.

Here is the situation, we have a client and a server which is running on two different machines. The client will basically pass a String to the server and the server will return an Object to the client. The Client will constantly feed the server with different Strings over a period of time.

I have noticed that if I keep connection to the server (i.e. using one instance of the Prx object with multiple Clients). The response time (from passing the String to the server to actually getting the result from the server) will be slower than if each Client has its own instance for the Prx object. Shouldn't creating one instance of the Prx object be faster since the Clients don't need to initialize the connection each time??

Also we have also noticed the greater the value of Ice.ThreadPool.Server.Size, the slower the response time. (i.e. having Pool size = 1 will be faster than Pool size = 10). So what is the use of the Pool if it actually degrade the performance? Or did I do something wrong?!?!


Any help would be appreciated. Thanks.
:)

Comments

  • I'm afraid I don't understand what you mean with "using one instance of the Prx object with multiple Clients". Clients cannot share proxies. Each proxy is instantiated in the client's physical process, and from each client there is a connection to the server.

    Or do you mean "logical" clients, i.e., you have several threads in one client process that all use the same proxy? In this case it doesn't matter if you use the same proxy instance or not, the connection to the server is shared in any case.

    With older versions of Ice, a connection is closed when the last proxy that uses the connection goes out of scope. This has proven to be impractical in certain cases, so from version 1.3.0 on, connections are only closed by active connection management. Here is the info from the CHANGES file:
    - Connections are no longer closed when the last proxy using the
    connection is destroyed. Doing so is error prone:

    * Quite often, proxies are created on the fly, resulting in
    connections being opened and closed all the time. This is
    especially true for services that receive a proxy and data, and
    then forward this data using the proxy.

    * Often, connections are stay open for too long, because proxies are
    kept even though they are never used again.

    * It doesn't work well with AMI requests, because the AMI callback
    objects keep track of connections directly. This would mean that
    if a process only uses AMI requests, a connection is opened and
    closed for each request, as each request typically has its own
    AMI callback object.

    Instead, ACM (Automatic Connection Management) is now enabled by
    default, with a default value of one minute. This means that idle
    connections are closed after one minute, regardless of whether there
    are proxies using the connection or not. This closing of connections
    is transparent, i.e., closed connections are automatically
    reestablished in case they are needed again. Please see the
    description of the Ice.ConnectionIdleTime property for details.

    As for you second question, you use the thread pool if you want to dispatch operations in parallel. If you only have one thread, and a client calls an operation that takes a long time to complete (for example, because it has to access the file system or a database), then no other operation could be dispatched in during this time.

    If you only have operations that complete immediately, then you should set the number of threads in the thread pool to the number of processors of the server host.
  • I hope I could explain it better... But here is what i mean (in java):

    Ice.Communicator ic = null;
    ic = Util.initialize(args);
    ObjectPrx base = ic.stringToProxy("Searcher:default -p 10000");
    if (base == null) {
    throw new RuntimeException("Cannot create proxy");
    }
    SearcherPrx searcher = SearcherPrxHelper.checkedCast(base);


    By sharing the instance of the searcher with the clients, I mean some class create an instance of the searcher above and pass it to the clients via the constructor for example. But as I said, it will run slower if I use this approach versus creating each client having their own instance of the searcher.

    Hope this will clear things up. Thanks for the reply.
  • I don't understand exactly what you are doing. What exactly is a "client" in your case? What do you mean by "create an instance of the searcher above and pass it to the clients via the constructor"? Do you mean that each "client" runs in its own thread? Or just that you simply have multiple intances of a class that holds a proxy to the server?

    At any rate, whether you create the proxy from a string in each "client" or just pass the proxy makes no difference -- behind the scenes, the connection object is shared anyway.

    Can you create simple, stand-alone example that illustrates the problem for us? We really need to see the code to work out what is going on.

    Thanks,

    Michi.
  • Sure, here is what I did.

    This runs slower:

    public SomeClass {

    public static void main(String[] args) {
    int status = 0;
    Ice.Communicator ic = null;
    try {
    ic = Util.initialize(args);
    ObjectPrx base = ic.stringToProxy("Searcher:default -p 10000");
    if (base == null) {
    throw new RuntimeException("Cannot create proxy");
    }
    SearcherPrx searcher = SearcherPrxHelper.checkedCast(base);

    for (int i=0; i < 10; i ++) {
    SomeThread worker = new SomeThread(searcher);
    worker.start();
    }
    } catch (LocalException e) {
    e.printStackTrace();
    status = -1;
    } catch (Exception e) {
    e.printStackTrace();
    System.err.println(e.getMessage());
    status = -1;
    } finally {
    if (ic != null) {
    ic.destroy();
    }
    }
    System.exit(status);
    }

    }

    This runs a bit faster:

    public class SomeThread {
    //...
    public void run() {
    Ice.Communicator ic = null;
    try {
    ic = Util.initialize(args);
    ObjectPrx base = ic.stringToProxy("Searcher:default -p 10000");
    if (base == null) {
    throw new RuntimeException("Cannot create proxy");
    }
    SearcherPrx searcher = SearcherPrxHelper.checkedCast(base);

    // ... do some work here with the searcher.
    } catch (LocalException e) {
    e.printStackTrace();
    } catch (Exception e) {
    e.printStackTrace();
    System.err.println(e.getMessage());
    } finally {
    if (ic != null) {
    ic.destroy();
    }
    }
    }
    }

    public class SomeClass {
    public static void main(String[] args) {
    for (int i=0; i < 10; i ++) {
    SomeThread worker = new SomeThread();
    worker.start();
    }
    }
    }
  • In your second example, you are creating one communicator per thread, not just one proxy per thread. For different communicators, different connections are used, so each proxy has it's own connection in the second example. Furthermore, new thread pools are created for each communicator.

    As to why it runs a bit faster, that's hard to say without knowing how many processors your hardware has, what kind of work the clients are exactly doing, etc. However, the 2nd solution definitely consumes a lot more resources, because you create 10 communicators instead of just one, and each communicator basically represents an independent Ice instance.