[MacRuby-devel] Speed

Joshua Ballanco jballanc at gmail.com
Thu Dec 22 07:41:56 PST 2011


2011/12/21 François Boone <francois.boone at usherbrooke.ca>

> Hi Josh,
>
> In macirb, I use:
> load "actionAffiche.rb"
> 461 queries, real time: 11.578257s
>
> In Xcode:
> I use rubygems and mysql macgems
> I have one Button and one table with two columns: when I press the button,
> the function actionAffiche is running. I think that it's a complete minimal
> example.
> 461 queries, real time: 64.244236s
> Apart MainMenu.xib, all my code is in AppDelegate.rb. I put this file at
> the end of this mail (Is there a better way?)
>
> I don't have control on mysql tables since they come from another software.
>
> I am a novice, then you can criticize my code :)
>

Not at all. Your code is quite ok. The only comments I would have is that
you should avoid using globals (variables starting with '$') whenever
possible, and your indenting is slightly non-traditional. Typically, in a
begin/rescue/ensure/end, all of the keywords are indented to the same level
so that it is easier to identify each block of the statement.


>
> Regards,
> François
>
> -------
> #
> #  AppDelegate.rb
> #  ecm: exemple complet minimal
> #
> #  Created by Boone François on 11-12-21.
> #  Copyright 2011 Boone François. All rights reserved.
> #
>
> require 'rubygems'
> require 'mysql'
>
> $data = []
>
> class AppDelegate
>    attr_accessor :window
>    def applicationDidFinishLaunching(a_notification)
>        # Insert code here to initialize your application
>    end
> end
>
> class CtrButton
>    attr_writer :individu
>
>    def awakeFromNib
>        @individu.dataSource = self
>        $ref_individu = @individu
>    end
>
>    def affiche(sender)
>        actionAffiche
>    end
>
>    def numberOfRowsInTableView(individu)
>        $data.size
>    end
>
>    def tableView(individu, objectValueForTableColumn:column, row:index)
>        item = $data[index]
>        case column.identifier
>            when 'iden'
>            item.iden
>            when 'name'
>            item.name
>        end
>    end
> end
>
> class Person
>    attr_accessor :iden, :name
> end
>
> def actionAffiche
>
>    t1 = Time.now
>    # Connexion au serveur MySQL
>    begin
>        dbh = Mysql.real_connect("localhost", "root", "", "Boone")
>        ## Récupération de la version du serveur et affichage
>        puts "Version du serveur: " + dbh.get_server_info
>        rescue Mysql::Error => e
>        puts "Code d'erreur : #{e.errno}"
>        puts "Message d'erreur : #{e.error}"
>        puts "SQLSTATE d'erreur : #{e.sqlstate}" if
> e.respond_to?("sqlstate")
>        ensure
>        dbh.query("SET NAMES utf8")
>    end
>
>    # Requête pour le nom de famille
>    dbh.query("SET NAMES utf8")
>    requete = "SELECT handle,surname FROM surname ORDER BY surname"
>    reponse = dbh.query(requete)
>
>    num_max = reponse.num_rows
>    num = 1
>
>    # Pour chaque nom de famille, on cherche le prenom
>    reponse.each_hash do |lastname|
>        puts "Individu " + num.to_s + " sur " + num_max.to_s
>        individu = Person.new
>        individu.iden = lastname["handle"]
>        individu.name = lastname["surname"]
>        # pour chaque nom, recherche du prenom à partir du handle.
>        requete2 = "SELECT first_name,xcall FROM name WHERE handle ='" +
> lastname["handle"] + "'"
>        reponse2 = dbh.query(requete2)
>        reponse2.each_hash do |firstname|
>            individu.name = individu.name + ", " + firstname["first_name"]
>            if firstname["xcall"] != ""
>                individu.name = individu.name + " (" + firstname["xcall"]
> + ")"
>            end
>        end
>
>        $data.push(individu)
>        num += 1
>    end
>
>    # On ferme le lien mySQL
>    dbh.close
>
>    t2 = Time.now
>    puts (t2-t1)
>    # Mise à jour de l'interface
>    $ref_individu.reloadData
> end


So, two quick comments. First, you don't have to put all of this code into
AppDelegate.rb. Instead, you can make new files for each class, just as you
would with any other Ruby project. I did something like this for the talk I
gave to Boston.rb last week (slides here:
http://www.slideshare.net/jballanc/macruby-for-fun-and-profit). However,
that is unrelated to the slowness you are observing.

The source of your slowness is here:

       $data.push(individu)

without seeing how you have everything hooked up, I can already guess that
this is causing updates to the UI after every query. Typically, updating a
UI is one of the slower things that you can do. An immediate speed up would
be to collect all of your query results into a temporary array, and then at
the end append them all to your $data object at once (but don't use a
global – probably better to make that a method in a class, and probably
better to write a separate class for your data source and UI controller –
but those changes aren't necessary for this fix).

- Josh

P.S. If you really want your UI to remain responsive while performing these
queries, then you will need to do the queries on a thread. Luckily, GCD
makes that relatively easy to do!
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-devel/attachments/20111222/3f49f675/attachment.html>


More information about the MacRuby-devel mailing list