Is it possible to make a background thread run faster? - ios

I am using RubyMotion and have a calendar implemented using CKCalendarView and I have the following code highlighting days on which events occur.
The following method is called from layoutSubviews
def calendarDidLayoutSubviews(calendar)
_events_array = []
if self.events
self.events.reverse.each do |ev|
mdy = ev.date.month_date_year
_events_array << mdy unless _events_array.include?(mdy)
end
end
Dispatch::Queue.main.async do
today = NSDate.date.month_date_year
if calendar.dateButtons && calendar.dateButtons.length > 0
calendar.dateButtons.each do |db|
db.backgroundColor = "f4f2ee".to_color
if db.date && db.date >= calendar.minimumDate && db.date <= calendar.maximumDate
if _events_array && _events_array.length > 0
db.setTitleColor("c7c3bb".to_color, forState:UIControlStateNormal)
db.backgroundColor = "f4f2ee".to_color
if _events_array.include?(db.date.month_date_year)
db.setTitleColor(UIColor.blackColor, forState:UIControlStateNormal)
db.backgroundColor = "9ebf6c".to_color
_events_array.delete(db.date.month_date_year)
end
end
end
if db.date && db.date.month_date_year == today
if calendar.minimumDate <= db.date && calendar.maximumDate >= db.date
db.setTitleColor(UIColor.blackColor, forState:UIControlStateNormal)
else
db.setTitleColor("f4f2ee".to_color, forState:UIControlStateNormal)
end
end
end
end
end
end
As it is, this freezes the UI for a .5 - 1.5s when drawing. If I move it in to a background thread, it takes 4 or 5 times as long to draw, but doesn't freeze the UI.
Question: Is there a way to give the background thread a higher priority, or a way to incrementally draw and highlight the dateButtons so that it doesn't look like nothing is happening in the half dozen seconds it takes to draw(when not in the main thread)?

The method I posted was getting called in the main thread, so I switched it to be called in a background thread, and then called the main thread for all drawing operations inside my loop.
def calendarDidLayoutSubviews(calendar)
_events_array = []
if self.events
self.events.reverse.each do |ev|
mdy = ev.date.month_date_year
_events_array << mdy unless _events_array.include?(mdy)
end
end
today = NSDate.date.month_date_year
if calendar.dateButtons && calendar.dateButtons.length > 0
calendar.dateButtons.each do |db|
Dispatch::Queue.main.async do
db.backgroundColor = "f4f2ee".to_color
end
if db.date && db.date >= calendar.minimumDate && db.date <= calendar.maximumDate
if _events_array && _events_array.length > 0
Dispatch::Queue.main.async do
db.setTitleColor("c7c3bb".to_color, forState:UIControlStateNormal)
db.backgroundColor = "f4f2ee".to_color
end
if _events_array.include?(db.date.month_date_year)
Dispatch::Queue.main.async do
db.setTitleColor(UIColor.blackColor, forState:UIControlStateNormal)
db.backgroundColor = "9ebf6c".to_color
end
_events_array.delete(db.date.month_date_year)
end
end
end
if db.date && db.date.month_date_year == today
if calendar.minimumDate <= db.date && calendar.maximumDate >= db.date
Dispatch::Queue.main.async do
db.setTitleColor(UIColor.blackColor, forState:UIControlStateNormal)
end
else
Dispatch::Queue.main.async do
db.setTitleColor("f4f2ee".to_color, forState:UIControlStateNormal)
end
end
end
end
end
end

Related

Rails replace if/elseif block by guard

I create a table of cash transactions inside of PDF using Prawn gem. To do so I iterate through the Hash with parsed_cash_transactions but before each is started I need to save the last_item of that Hash to check when I should display the summary table below the main table.
def transactions_row
last_item = parsed_cash_transactions.last[:position]
parsed_cash_transactions.each do |cash_transaction|
# some operations with cash_transaction item
table_end_position = cursor
if last_item == cash_transaction[:position] && table_end_position < 204
new_page
draw_gray_line if cash_transaction[:position].to_i.even?
elsif table_end_position < 15
new_page
draw_gray_line if cash_transaction[:position].to_i.even?
end
end
end
To deal with all requirements I've got if block below. I'm wondering is there a better, cleaner way to replace that if block? maybe I could use guard somehow?
if last_item == cash_transaction[:position] && table_end_position < 204
new_page
draw_gray_line if cash_transaction[:position].to_i.even?
elsif table_end_position < 15
new_page
draw_gray_line if cash_transaction[:position].to_i.even?
end
You could indeed use a guard clause, although it is not the most pretty, since it condition is pretty long.
def transactions_row
last_item = parsed_cash_transactions.last[:position]
parsed_cash_transactions.each do |cash_transaction|
# some operations with cash_transaction item
table_end_position = cursor
next unless last_item == cash_transaction[:position] && table_end_position < 204 ||
table_end_position < 15
new_page
draw_gray_line if cash_transaction[:position].to_i.even?
end
end

Rails break and return not working

I'm working with koala. I have to check the permission given is granted by user for the application. I have made a helper called facebook helper. There is a def has_permission?(perm). My code follows:
def has_permission? (perm)
#graph = Koala::Facebook::API.new(current_user.token)
#permissions = #graph.get_connections('me', 'permissions')
#bool = false
#permissions.each do |p|
if p[0] == perm && p[1] == 'granted'
#bool = true
break
end
end
return #bool
end
It always returns false. What is wrong with this ?
Is your #permissions getting populated? You can also write this without the break
def has_permission? (perm)
#graph = Koala::Facebook::API.new(current_user.token)
#permissions = #graph.get_connections('me', 'permissions')
#bool = false
#permissions.each do |p|
unless #bool
#bool = (p[0] == perm && p[1] == 'granted')
end
end
#bool
end
I would also move the p[0] == perm && p[1] == 'granted' into its own method for better readability.
I solved it myself:
def has_permission? (perm)
#graph = Koala::Facebook::API.new(current_user.token)
#permissions = #graph.get_connections('me', 'permissions')
# binding.pry
#bool = false
#permissions.each do |p|
if (p['permission'] == perm && p['status'] == 'granted')
#bool = true
break
end
end
#bool
end
Just changed p[0] to p['permission'] and p[1] to p['status']

Testing whether a Ruby object is in fact waiting

I have a system, comprised of a BoundedQueue class, a Producer class that pushes items into a BoundedQueue object and a Consumer class that takes items out of the BoundedQueue object, the Producer and Consumer exist on separate threads. So that items aren't lost when they're pushed to a full queue I use a condition variable and a mutex to tell the Producer to wait until the queue has a space.
I need to create a test case that checks that the Producer is waiting when the queue is full, I'm not sure if I'm being ditsy or not but I just can't think of how to do this properly.
BoundedQueue class:
class BoundedQueue
attr_reader :count
def initialize(size)
#mutex = Mutex.new
#rep = Array.new(size) if size > 0
#size = size
#back = size-1
#front = 0
#count = 0
#condvar = ConditionVariable.new
end
def isEmpty?
#count == 0
end
def isFull?
#count == #size
end
def put(item)
#mutex.synchronize do
if item != nil
while isFull?
#condvar.wait(#mutex)
end
#back += 1
#back = 0 if #back >= #size
#rep[#back] = item
#count += 1
end
end
end
def get
#mutex.synchronize do
result = nil
if (!isEmpty?)
result = #rep[#front]
#rep[#front] = nil
#front += 1
#front = 0 if #front >= #size
#count -= 1
#condvar.signal
end
result
end
end
end
Producer class:
class Producer
def initialize(id, no_items, queue)
#id = "Producer#{id}"
#no_items = no_items
#queue = queue
end
def produce
while #no_items != 0
#queue.put("Item #{#no_items} from #{#id} ")
puts "#{#id} putting item #{#no_items} into the queue "
#no_items -= 1
end
end
end
Consumer class:
class Consumer
def initialize(queue)
#queue = queue
end
def consume
while !#queue.isEmpty?
puts "#{#queue.get} consumed from the queue"
sleep(Random.rand(10))
end
end
end
The test case so far:
require "./boundedQueue.rb"
require "./producer.rb"
require "./consumer.rb"
mutex = Mutex.new
cv = ConditionVariable.new
test_queue = BoundedQueue.new(5)
puts "Creating the producer"
producerOne = Producer.new(0,7,test_queue)
puts "Creating consumer"
consumer = Consumer.new(test_queue)
puts "Creating threads"
a = Thread.new{
producerOne.produce
}
b = Thread.new{
consumer.consume
}
puts "Joining threads"
b.join
a.join

Ruby: Looping through models to calculate ratios within nested hashes

I'm building a spam filter for a job app (think tinder for jobs). I'm currently helping to build a spam filter. To achieve that goal, a signal for users who are "over-applying" for jobs is their apply-to-rejection ratio per day.
To inform our threshold, I've come up with a solution to gather that data from the db by using a nested hash i.e. {user1 =>{date1=>0.33, date2=>0.66}}. My problem now is that the ratios are all 1.0, because i think i'm looping up until either rejections or applications are all gone through so the calculation is always the same number divided by itself.
Here's what i got so far. Appreciate the help.
users = User.all
ratio_hash = Hash.new
users.each do |user|
if user.job_applications.count > 0 && user.job_rejections.count > 0
ratio_hash[user.name] = Hash.new
apply_array = []
reject_array = []
user.job_rejections.each do |reject|
user.job_applications.each do |apply|
if (apply.user_id.present? && reject.user_id.present?) || rej.user_id.present?
if (apply.user_id == user.id && reject.user_id == user.id) || rej.user_id == user.id
if (apply.created_at.present? && reject.created_at.present?) || reject.created_at.present?
date = (apply_array && reject.created_at.to_date)
if (apply.created_at.to_date == reject.created_at.to_date) || reject.created_at.to_date == date
apply_array << apply.created_at.to_date
reject_array << reject.created_at.to_date
ratio_hash[user.name][(apply.created_at.to_date || reject.created_at.to_date)] = (apply_array.length.round(2)/reject_array.length)
end
end
end
end
end
end
end
end

Run Rake Task without using Rake

I have an app where users can bet each other and when the result are loaded into the app I use a Rake task to settle the bets. I'm running on Heroku so I'm using their Schedule service for this Rake task every half hour.
This works fine, but I would much more like to run the Rake job when the results are saved/updated in the database.
How do I convert the Rake task so I can run it from my model, which could look like the below. It could also be nice if I could run it from the controllers, since I might have several situations where a settlement process is needed.
class Spotprice < ActiveRecord::Base
belongs_to :spotarea
belongs_to :product
after_save :settlement
end
My Rake task looks like this right now:
task :settlement => :environment do
puts "Settlement in progress..."
puts "-------------------------"
puts " "
puts " "
puts "BETS:"
puts "-------------------------"
# Bet settlement
#bets = Bet.where(:settled => false)
#bets.find_each do |bet|
if not bet.choice.spotprice.nil?
case
when bet.choice.spotprice.value > bet.choice.value && bet.buy == true
profitloss = 10
puts "#{bet.id}: Win (1)"
when bet.choice.spotprice.value < bet.choice.value && bet.buy == false
profitloss = 10
puts "#{bet.id}: Win (2)"
when bet.choice.spotprice.value > bet.choice.value && bet.buy == false
profitloss = -10
puts "#{bet.id}: Loose (3)"
when bet.choice.spotprice.value < bet.choice.value && bet.buy == true
profitloss = -10
puts "#{bet.id}: Loose (4)"
when bet.choice.spotprice.value == bet.choice.value
profitloss = -10
puts "#{bet.id}: Loose (5)"
end
if profitloss
bet.settled = true
bet.profitloss = profitloss
bet.save
end
end
if bet.choice.settled == true
bet.choice.settled = false
bet.choice.save
end
end
# Pusher update
Pusher["actives"].trigger("updated", {:message => "Settlement completed"}.to_json)
end
Just putting my comments from the original question in to an answer.
I had a similar situation where I had a rake task that I wanted to call from outside of rake. What you want to do is move the code from the rake task in to a ruby class, the best place for this would be in lib. Your class would look something like this:
# lib/settlement.rb
class Settlement
def self.settle_bets
# all the code that used to be in the rake task
end
end
Then in code you can do something like this (random example):
# app/controllers/bets_controller.rb
#...
def settle_bets
require "settlement"
Settlement.settle_bets
end
# ...
Or (another random example):
# app/models/bet.rb
class Bet ...
after_update: update_some_bets
# ... more code here
private
def update_some_bets
require "settlement"
Settlement.settle_bets
end
And you could still use the rake task if you wanted:
# lib/tasks/settlement.task
require "settlement"
# require "#{Rails.root}/lib/settlement.rb" # use this if the above won't work
task :settlement => :environment do
Settlement.settle_bets
end
If you want the results calculated when you update (or save), why not move most of the code from your rake task into a method of your Bet model, then call it which you call with an after_update callback
in bet.rb
# class method that settles the given bet
def self.settle(bet)
message = nil
if not bet.choice.spotprice.nil?
case
when bet.choice.spotprice.value > bet.choice.value && bet.buy == true
profitloss = 10
message = "#{bet.id}: Win (1)"
when bet.choice.spotprice.value < bet.choice.value && bet.buy == false
profitloss = 10
message = "#{bet.id}: Win (2)"
when bet.choice.spotprice.value > bet.choice.value && bet.buy == false
profitloss = -10
message = "#{bet.id}: Lose (3)"
when bet.choice.spotprice.value < bet.choice.value && bet.buy == true
profitloss = -10
message = "#{bet.id}: Lose (4)"
when bet.choice.spotprice.value == bet.choice.value
profitloss = -10
message = "#{bet.id}: Lose (5)"
end
if profitloss
bet.settled = true
bet.profitloss = profitloss
bet.save
end
end
if bet.choice.settled == true
bet.choice.settled = false
bet.choice.save
end
# return message
message
end
in spot_price.rb
class SpotPrice
after_update Bet.settle(self)
after_save Bet.settle(self)
....
end
This doesn't handle the Pusher stuff our other output (which is saved and returned in the message variable). Also, couldn't help myself, but I assumed you mean "Lose", not "Loose".
Is this what you're looking for?

Resources