aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortoshi <toshi@03aab468-d3d2-4883-8b12-f661bbf03fa8>2012-03-20 16:26:00 +0000
committertoshi <toshi@03aab468-d3d2-4883-8b12-f661bbf03fa8>2012-03-20 16:26:00 +0000
commit4676aecf38532483ecc33ac5180d63b5042097f8 (patch)
tree07c34dca135fa82d725101ee9bb376808cd6706d
parentae993e14d8a46bb93f1ae26d2ae574d85ab0fed0 (diff)
downloadmikutter-4676aecf38532483ecc33ac5180d63b5042097f8.tar.gz
処理を適当に切り分けて少しづつループする Enumerable#deach を追加。長時間UIスレッドを使ってしまうループでこれを使うようにした
git-svn-id: svn://toshia.dip.jp/mikutter/trunk@715 03aab468-d3d2-4883-8b12-f661bbf03fa8
-rw-r--r--core/addon/extract.rb4
-rw-r--r--core/addon/image_file_cache/image_file_cache.rb2
-rw-r--r--core/addon/list/liststream.rb2
-rw-r--r--core/delayer.rb21
-rw-r--r--core/lib/deferred/deferred.rb29
-rw-r--r--core/lib/deferred/deferredable.rb9
-rw-r--r--core/lib/deferred/test.deferred.rb24
-rw-r--r--core/lib/mikutwitter/api_call_support.rb40
-rw-r--r--core/mui/cairo_miracle_painter.rb16
-rw-r--r--core/mui/cairo_sub_parts_favorite.rb18
-rw-r--r--core/mui/cairo_sub_parts_retweet.rb8
-rw-r--r--core/mui/cairo_timeline.rb4
-rw-r--r--core/plugin.rb14
13 files changed, 118 insertions, 73 deletions
diff --git a/core/addon/extract.rb b/core/addon/extract.rb
index 161df116..72f23633 100644
--- a/core/addon/extract.rb
+++ b/core/addon/extract.rb
@@ -95,13 +95,13 @@ Module.new do
def hook_plugin(event)
Plugin.create(:extract).add_event(event){ |service, messages|
- tabclass.tabs.each{ |tab| tab.__send__("event_#{event}", messages) } }
+ tabclass.tabs.deach{ |tab| tab.__send__("event_#{event}", messages) } }
end
def boot_plugin
[:update,:mention,:posted].each{ |event| hook_plugin(event) }
Plugin.create(:extract).add_event(:appear){ |messages|
- tabclass.tabs.each{ |tab| tab.__send__("event_appear", messages) } }
+ tabclass.tabs.deach{ |tab| tab.__send__("event_appear", messages) } }
end
def tabclass
diff --git a/core/addon/image_file_cache/image_file_cache.rb b/core/addon/image_file_cache/image_file_cache.rb
index 4c307fa6..c2445794 100644
--- a/core/addon/image_file_cache/image_file_cache.rb
+++ b/core/addon/image_file_cache/image_file_cache.rb
@@ -9,7 +9,7 @@ Plugin.create :image_file_cache do
# appear_limit 回TLに出現したユーザはキャッシュに登録する
# (30分ツイートしなければカウンタはリセット)
onappear do |messages|
- messages.each { |message|
+ messages.deach { |message|
image_url = message.user[:profile_image_url]
if not j_include?(image_url)
appear_counter[image_url] ||= 0
diff --git a/core/addon/list/liststream.rb b/core/addon/list/liststream.rb
index 3949213c..01e71f81 100644
--- a/core/addon/list/liststream.rb
+++ b/core/addon/list/liststream.rb
@@ -33,7 +33,7 @@ Plugin::create(:liststream) do
member_anything - Plugin.filtering(:followings, Set.new).first end
def start
- service = Service.services.first
+ service = Service.primary
Thread.new{
loop{
sleep(3)
diff --git a/core/delayer.rb b/core/delayer.rb
index 385664c2..b7636b1c 100644
--- a/core/delayer.rb
+++ b/core/delayer.rb
@@ -51,18 +51,31 @@ class Delayer
debugging_wait
begin
@busy = true
- st = Process.times.utime
+ @st = Process.times.utime
3.times{ |cnt|
procs = []
if not @@routines[cnt].empty? then
procs = @@routines[cnt].clone
procs.each{ |routine|
- @@routines[cnt].delete(routine)
- routine.run
- return if ((Process.times.utime - st) > 0.1) } end }
+ if Mopt.debug
+ r_start = Process.times.utime
+ @@routines[cnt].delete(routine)
+ routine.run
+ if (r_end = Process.times.utime - r_start) > 0.1
+ open(File.expand_path(File.join(Environment::LOGDIR, "delayer.late.log")), "a"){ |io|
+ bt = routine.backtrace.find{ |bt| not bt.include?('delayer') }
+ bt = routine.backtrace.first if not bt
+ io.puts("#{r_end},#{bt.gsub(FOLLOW_DIR, '{MIKUTTER_DIR}')}") }
+ end
+ else
+ routine.run end
+ return if time_limit? } end }
ensure
@busy = false end end
+ def self.time_limit?
+ (Process.times.utime - @st) > 0.02 end
+
# Delayerのタスクを消化中ならtrueを返す
def self.busy?
@busy end
diff --git a/core/lib/deferred/deferred.rb b/core/lib/deferred/deferred.rb
index 0b2beb89..3035643b 100644
--- a/core/lib/deferred/deferred.rb
+++ b/core/lib/deferred/deferred.rb
@@ -5,6 +5,7 @@ class Deferred
def initialize(follow = nil)
@follow = follow
+ @backtrace = caller if Mopt.debug
end
alias :deferredable_cancel :cancel
@@ -66,22 +67,18 @@ class Thread
end
module Enumerable
- def aeach(&proc)
- start_time = 0
- ary = to_a
- limit = ary.size
- index = 0
- peace = lambda{
- start_time = Time.new.to_f
- while(index >= limit)
- if (Time.new.to_f - start_time) >= 0.01
- peace.call
- break deferred{ peace.call }
- else
- result = proc.call(ary[index])
- index += 1
- result end end }
- deferred{ peace.call }
+ # 遅延each。あとで実行されるし、あんまりループに時間がかかるようなら一旦ループを終了する
+ def deach(&proc)
+ iteratee = to_a
+ iteratee = dup if equal?(iteratee)
+ deferred{
+ result = nil
+ while not iteratee.empty?
+ item = iteratee.shift
+ proc.call(item)
+ if Delayer.time_limit?
+ break result = iteratee.deach(&proc) end end
+ result }
end
end
diff --git a/core/lib/deferred/deferredable.rb b/core/lib/deferred/deferredable.rb
index 98aa8705..15d07583 100644
--- a/core/lib/deferred/deferredable.rb
+++ b/core/lib/deferred/deferredable.rb
@@ -2,6 +2,9 @@
# なんでもDeferred
module Deferredable
+
+ attr_reader :backtrace
+
# このDeferredが成功した場合の処理を追加する。
# 新しいDeferredのインスタンスを返す
def next(&proc)
@@ -82,7 +85,11 @@ module Deferredable
@next end }
else
if defined?(@next)
- Delayer.new{ @next.call(n_value) }
+ if Mopt.debug
+ this = self
+ Delayer.new{ @next.call(n_value) }.instance_eval{ @backtrace = this.backtrace }
+ else
+ Delayer.new{ @next.call(n_value) } end
else
regist_next_call(:ok, n_value) end end
throw :__deferredable_success
diff --git a/core/lib/deferred/test.deferred.rb b/core/lib/deferred/test.deferred.rb
index 0708b413..47c84f03 100644
--- a/core/lib/deferred/test.deferred.rb
+++ b/core/lib/deferred/test.deferred.rb
@@ -87,10 +87,12 @@ class TC_Deferred < Test::Unit::TestCase # !> method redefined; discarding old f
Thread.new{
39
}.next{ |x|
- ans = x # !> method redefined; discarding old _post
+ x + 1 # !> method redefined; discarding old _post
+ }.next{ |x|
+ ans = x
}
wait_all_tasks
- assert_equal(39, ans)
+ assert_equal(40, ans)
end
def test_thread_error
@@ -184,19 +186,17 @@ class TC_Deferred < Test::Unit::TestCase # !> method redefined; discarding old f
assert_equal(0, ans)
end
- # def test_aeach
- # a = 0
- # (1..1000000).aeach{
- # Time.new
- # a += 1
- # }
- # Delayer.run
- # assert_equal(1000000, a)
- # end
+ def test_deach
+ a = 0
+ (1..100000).deach{
+ a += 1
+ }
+ wait_all_tasks
+ assert_equal(100000, a)
+ end
end
-
# >> Loaded suite -
# >> Started
# >> F.F....
diff --git a/core/lib/mikutwitter/api_call_support.rb b/core/lib/mikutwitter/api_call_support.rb
index 7d172944..bdf0c99b 100644
--- a/core/lib/mikutwitter/api_call_support.rb
+++ b/core/lib/mikutwitter/api_call_support.rb
@@ -41,7 +41,7 @@ module MikuTwitter::ApiCallSupport
define_method(multi){ |options = {}|
type_strict options => Hash
json(defaults.merge(options)).next{ |node|
- node.map(&parser) } }
+ Thread.new{ node.map(&parser) } } }
define_method(uni){ |options = {}|
type_strict options => Hash
@@ -69,7 +69,7 @@ module MikuTwitter::ApiCallSupport
def json(options)
type_strict options => Hash
twitter.api(api, options, force_oauth).next{ |res|
- JSON.parse(res.body).symbolize } end
+ Thread.new{ JSON.parse(res.body).symbolize } } end
defparser :user
defparser :message, :messages, include_entities: 1
@@ -79,7 +79,7 @@ module MikuTwitter::ApiCallSupport
def messages(options = {})
type_strict options => Hash
- json({include_entities: 1}.merge(options)).next(&Parser.method(:messages)) end
+ json({include_entities: 1}.merge(options)).next{ |m| Thread.new{ Parser.messages m } } end
def friendship(options = {})
type_strict options => Hash
@@ -93,23 +93,23 @@ module MikuTwitter::ApiCallSupport
def search(options = {})
type_strict options => Hash
json(options).next{ |res|
- res[:results].map{ |msg|
- cnv = msg.convert_key(:text => :message,
- :to_user_id => :receiver,
- :in_reply_to_status_id => :replyto)
- user = {
- id: msg[:from_user_id],
- idname: msg[:from_user],
- name: msg[:from_user_name],
- profile_image_url: msg[:profile_image_url]
- }
- cnv[:user] = Message::MessageUser.new(User.new_ifnecessary(user), user)
- if cnv[:source].is_a?(String) and
- cnv[:source].gsub(/&\w+?;/){ |m| HTML_ATTR_UNESCAPE_HASH[m] }.match(/^<a\s+.*>(.*?)<\/a>$/)
- cnv[:source] = $1 end
- cnv[:created] = (Time.parse(msg[:created_at]) rescue Time.now)
- Message.new_ifnecessary(cnv)
- } } end
+ Thread.new {
+ res[:results].map{ |msg|
+ cnv = msg.convert_key(:text => :message,
+ :to_user_id => :receiver,
+ :in_reply_to_status_id => :replyto)
+ user = {
+ id: msg[:from_user_id],
+ idname: msg[:from_user],
+ name: msg[:from_user_name],
+ profile_image_url: msg[:profile_image_url]
+ }
+ cnv[:user] = Message::MessageUser.new(User.new_ifnecessary(user), user)
+ if cnv[:source].is_a?(String) and
+ cnv[:source].gsub(/&\w+?;/){ |m| HTML_ATTR_UNESCAPE_HASH[m] }.match(/^<a\s+.*>(.*?)<\/a>$/)
+ cnv[:source] = $1 end
+ cnv[:created] = (Time.parse(msg[:created_at]) rescue Time.now)
+ Message.new_ifnecessary(cnv) } } } end
def inspect
"#<#{MikuTwitter::ApiCallSupport::Request}: #{@api}>"
diff --git a/core/mui/cairo_miracle_painter.rb b/core/mui/cairo_miracle_painter.rb
index 8f493b89..991c9e85 100644
--- a/core/mui/cairo_miracle_painter.rb
+++ b/core/mui/cairo_miracle_painter.rb
@@ -38,7 +38,8 @@ class Gdk::MiraclePainter < Gtk::Object
# @@miracle_painters = Hash.new
- # _message_ を内部に持っているGdk::MiraclePainterの集合をSetで返す
+ # _message_ を内部に持っているGdk::MiraclePainterの集合をSetで返す。
+ # ログ数によってはかなり重い処理なので注意
def self.findbymessage(message)
type_strict message => :to_message
message = message.to_message
@@ -47,7 +48,18 @@ class Gdk::MiraclePainter < Gtk::Object
found = tl.get_record_by_message(message)
result << found.miracle_painter if found }
result.freeze
- # @@miracle_painters[message.to_message[:id].to_i] || EMPTY
+ end
+
+ # findbymessage のdeferred版。
+ def self.findbymessage_d(message)
+ type_strict message => :to_message
+ message = message.to_message
+ result = Set.new
+ Gtk::TimeLine.timelines.deach{ |tl|
+ found = tl.get_record_by_message(message)
+ result << found.miracle_painter if found
+ }.next{
+ result.freeze }
end
def initialize(message, *coodinate)
diff --git a/core/mui/cairo_sub_parts_favorite.rb b/core/mui/cairo_sub_parts_favorite.rb
index edd51d9a..02dde4f9 100644
--- a/core/mui/cairo_sub_parts_favorite.rb
+++ b/core/mui/cairo_sub_parts_favorite.rb
@@ -21,18 +21,24 @@ class Gdk::SubPartsFavorite < Gdk::SubPartsVoter
Delayer.new{
Plugin.create(:core) do
onfavorite do |service, user, message|
- Gdk::MiraclePainter.findbymessage(message).each{ |mp|
- mp.subparts.find{ |sp| sp.class == Gdk::SubPartsFavorite }.add(user) }
+ Gdk::MiraclePainter.findbymessage_d(message).next{ |mps|
+ mps.deach{ |mp|
+ if not mp.destroyed?
+ mp.subparts.find{ |sp| sp.class == Gdk::SubPartsFavorite }.add(user) end } }
end
on_before_favorite do |service, user, message|
- Gdk::MiraclePainter.findbymessage(message).each{ |mp|
- mp.subparts.find{ |sp| sp.class == Gdk::SubPartsFavorite }.add(user) }
+ Gdk::MiraclePainter.findbymessage_d(message).next{ |mps|
+ mps.deach{ |mp|
+ if not mp.destroyed?
+ mp.subparts.find{ |sp| sp.class == Gdk::SubPartsFavorite }.add(user) end } }
end
on_fail_favorite do |service, user, message|
- Gdk::MiraclePainter.findbymessage(message).each{ |mp|
- mp.subparts.find{ |sp| sp.class == Gdk::SubPartsFavorite }.delete(user) }
+ Gdk::MiraclePainter.findbymessage_d(message).next{ |mps|
+ mps.deach{ |mp|
+ if not mp.destroyed?
+ mp.subparts.find{ |sp| sp.class == Gdk::SubPartsFavorite }.delete(user) end } }
end
end
}
diff --git a/core/mui/cairo_sub_parts_retweet.rb b/core/mui/cairo_sub_parts_retweet.rb
index c3aa36e7..2878397d 100644
--- a/core/mui/cairo_sub_parts_retweet.rb
+++ b/core/mui/cairo_sub_parts_retweet.rb
@@ -20,14 +20,14 @@ class Gdk::SubPartsRetweet < Gdk::SubPartsVoter
Delayer.new{
Plugin.create(:core).add_event(:retweet){ |retweets|
- retweets.each{ |retweet|
- Delayer.new{
- Gdk::MiraclePainter.findbymessage(retweet.retweet_source(true)).each{ |mp|
+ retweets.deach{ |retweet|
+ Gdk::MiraclePainter.findbymessage_d(retweet.retweet_source(true)).next{ |mps|
+ mps.deach{ |mp|
if not mp.destroyed?
begin
mp.subparts.find{ |sp| sp.class == Gdk::SubPartsRetweet }.add(retweet[:user])
mp.on_modify
rescue Gtk::MiraclePainter::DestroyedError
- nil end end } } } } }
+ nil end end } }.terminate("retweet error") } } }
end
diff --git a/core/mui/cairo_timeline.rb b/core/mui/cairo_timeline.rb
index 4ed72332..6c1a652f 100644
--- a/core/mui/cairo_timeline.rb
+++ b/core/mui/cairo_timeline.rb
@@ -140,7 +140,7 @@ class Gtk::TimeLine
remove_if_exists_all(removes)
retweets, appends = *messages.partition{ |m| m[:retweet] }
add_retweets(retweets)
- appends.sort_by{ |m| -(m.modified.to_i) }.each(&method(:block_add))
+ appends.sort_by{ |m| -(m.modified.to_i) }.deach(&method(:block_add))
end
# リツイートを追加する。 _messages_ には Message の配列を指定し、それらはretweetでなければならない
@@ -199,7 +199,7 @@ class Gtk::TimeLine
when message[:rule] == :destroy
remove_if_exists_all([message])
when message.retweet?
- add_retweets([messages])
+ add_retweets([message])
else
_add(message) end end end
self end
diff --git a/core/plugin.rb b/core/plugin.rb
index b595bd95..c5fb2dc0 100644
--- a/core/plugin.rb
+++ b/core/plugin.rb
@@ -258,7 +258,16 @@ class Plugin
# plugin_loopの簡略化版。プラグインに引数 _args_ をそのまま渡して呼び出す
def plugin_callback_loop(ary, event_name, kind, *args)
plugin_loop(ary, event_name, kind){ |tag, proc|
- proc.call(*args){ throw(:plugin_exit) } } end
+ if Mopt.debug
+ r_start = Process.times.utime
+ result = proc.call(*args){ throw(:plugin_exit) }
+ if (r_end = Process.times.utime - r_start) > 0.1
+ open(File.expand_path(File.join(Environment::LOGDIR, "plugin.late.log")), "a"){ |io|
+ notice "#{r_end},#{tag.name},#{event_name},#{kind}"
+ io.puts("#{r_end},#{tag.name},#{event_name},#{kind}") } end
+ result
+ else
+ proc.call(*args){ throw(:plugin_exit) } end } end
# _ary_ [ _event\_name_ ] に登録されているプラグイン一つひとつを引数に _proc_ を繰り返し呼ぶ。
# _proc_ のシグニチャは以下の通り。
@@ -285,7 +294,8 @@ class Plugin
# ブロックの実行時間を記録しながら実行
def call_routine(plugintag, event_name, kind)
- catch(:plugin_exit){ yield } end
+ catch(:plugin_exit){ yield }
+ end
# 登録済みプラグインの一覧を返す。
# 返すHashは以下のような構造。