parallelQueue 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +27 -0
- data/README.rdoc +111 -0
- data/gemspec.parallelQueue +22 -0
- data/lib/parallelQueue.rb +69 -0
- data/test/test_parallelQueue.rb +57 -0
- metadata +53 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 24af9cbe3c3f6100ad83835d65e0dd239b7fd571
|
4
|
+
data.tar.gz: 040fed41dad97007807acf19a58b05691ca9a21a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 520aaa05828f84cf4247e1367074a680c4c13207750180f4d67aa0383660bcc2ca6bf527d72d1d1dbb230ce12570258f451e1bf39b0e4613827e19ca8a4201f1
|
7
|
+
data.tar.gz: e9f8e61f9f347e326da28ff0286c356ad0f9ece706bb404ecffba87f9b2e6d014cbfa4b1263bd153e56b152ed2dcc8e57004461153cc3a90ca9f6b9b99960fe6
|
data/LICENSE
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
Copyright (c) 2011-2014, Ralf Mueller (stark.dreamdetective@googlemail.com)
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
* Redistributions of source code must retain the above copyright notice,
|
8
|
+
this list of conditions and the following disclaimer.
|
9
|
+
|
10
|
+
* Redistributions in binary form must reproduce the above copyright
|
11
|
+
notice, this list of conditions and the following disclaimer in the
|
12
|
+
documentation and/or other materials provided with the distribution.
|
13
|
+
|
14
|
+
* The names of its contributors may not be used to endorse or promote
|
15
|
+
products derived from this software without specific prior written
|
16
|
+
permission.
|
17
|
+
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
19
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
20
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
21
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
22
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
23
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
24
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
25
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
26
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
27
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
= JobQueue - Let run your jobs in parallel
|
2
|
+
|
3
|
+
This package contains jobQueue:
|
4
|
+
* A simple class to parallalize your work on a user definend number of threads
|
5
|
+
* A ruby script, which uses the above class to run each line of a shell script
|
6
|
+
|
7
|
+
jobQueue can do the following things:
|
8
|
+
|
9
|
+
* Run blocks, Procs and Lambdas
|
10
|
+
* Run instance and class methods
|
11
|
+
* Run shell commands
|
12
|
+
* Respect user definded locks
|
13
|
+
|
14
|
+
I started a python2 implementation of this, which can be installed via pip
|
15
|
+
(https://pypi.python.org/pypi/jobqueue). When its maature enough, I will use
|
16
|
+
the ruby version numbers for it.
|
17
|
+
|
18
|
+
== Installation
|
19
|
+
|
20
|
+
=== Gem Installation
|
21
|
+
|
22
|
+
Download and install jobQueue with the following.
|
23
|
+
|
24
|
+
gem install jobQueue
|
25
|
+
|
26
|
+
=== Requirements
|
27
|
+
|
28
|
+
JobQueue requires Ruby only, but versions 1.9.x are needed to make use of system threads.
|
29
|
+
|
30
|
+
== Usage
|
31
|
+
|
32
|
+
=== Parallelize Ruby's blocks, procs, lambdas and things
|
33
|
+
|
34
|
+
Create a JobQueue with nThreads worker with:
|
35
|
+
|
36
|
+
jq = JobQueue.new(nThreads)
|
37
|
+
|
38
|
+
Use its push method to put in something to do
|
39
|
+
|
40
|
+
* For blocks:
|
41
|
+
jq.push do
|
42
|
+
myObject.method0(...)
|
43
|
+
myObject.method1(...)
|
44
|
+
myObject.method3(...)
|
45
|
+
end
|
46
|
+
|
47
|
+
* For procs and lambdas:
|
48
|
+
|
49
|
+
jp.push(myProc,arg0,arg1,...)
|
50
|
+
|
51
|
+
* For object methods:
|
52
|
+
|
53
|
+
jq.push([myObject,[:method,arg0,arg1,...])
|
54
|
+
|
55
|
+
* Same code can be used for class methods:
|
56
|
+
|
57
|
+
jq.push(myClass,[:myClassMethod,arg0,arg1,...])
|
58
|
+
|
59
|
+
To start the workers, call
|
60
|
+
|
61
|
+
jq.run
|
62
|
+
|
63
|
+
That's it. You might have look at tests, that come with the jobQueue gem.
|
64
|
+
|
65
|
+
=== Parallelize system commands
|
66
|
+
|
67
|
+
Use a separate class for this and push string to it:
|
68
|
+
|
69
|
+
jq = SystemJobs.new(nThreads)
|
70
|
+
jq.push('find ./src -name "*.rb"','find ./downloads -name "*.rb"')
|
71
|
+
|
72
|
+
will start 2 parallel searches for ruby files. This is implemented in the
|
73
|
+
prun.rb script, which comes with the jobQueue gem. To run each line of a shell
|
74
|
+
script on 10 threads, use:
|
75
|
+
|
76
|
+
prun.rb -j 10 jobs.sh
|
77
|
+
|
78
|
+
The '-j' switch is optional. Default is the maximum number of cores. The script
|
79
|
+
accepts multiple files and processes one after another. Try '-h' for documentation.
|
80
|
+
|
81
|
+
== Support, Issues, Bugs, ...
|
82
|
+
|
83
|
+
please use personal mail, ruby-lang mailing list or github
|
84
|
+
|
85
|
+
== Changelog
|
86
|
+
|
87
|
+
* 1.0.11: prun.rb now ignores empty lines
|
88
|
+
* 1.0.10: more flexible logging control (new switches '-l' and '-b')
|
89
|
+
* 1.0.9: print out stdout and stderr from the jobs given to prun.rb, use '-D' to avoid printing
|
90
|
+
* 1.0.8: support AIX for getting the maximum number of processors, improve processor count for jruby and rbx
|
91
|
+
|
92
|
+
== Credits
|
93
|
+
|
94
|
+
[<b>Robert Klemme</b>] For the first hints: https://www.ruby-forum.com/topic/68001#86298
|
95
|
+
|
96
|
+
== License
|
97
|
+
|
98
|
+
jobQueue use the BSD License
|
99
|
+
|
100
|
+
:include LICENSE
|
101
|
+
|
102
|
+
|
103
|
+
---
|
104
|
+
|
105
|
+
= Other stuff
|
106
|
+
|
107
|
+
Author:: Ralf Mueller <stark.dreamdetective@gmail.com>
|
108
|
+
Requires:: Ruby 1.9 or later
|
109
|
+
License:: Copyright 2011-2016 by Ralf Mueller
|
110
|
+
Released under BSD-style license. See the LICENSE
|
111
|
+
file included in the distribution.
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
spec = Gem::Specification.new do |s|
|
4
|
+
s.name = "parallelQueue"
|
5
|
+
s.version = '1.0.0'
|
6
|
+
s.platform = Gem::Platform::RUBY
|
7
|
+
s.files = ["lib/parallelQueue.rb"] + ["gemspec.parallelQueue","LICENSE","README.rdoc"]
|
8
|
+
s.description = "Extension 'parallel': Interface for pushung blocks"
|
9
|
+
s.summary = "This is a small extension to the 'parallel' library. It \
|
10
|
+
allows to push abitrary blocks to a Queue and execute them in parallel, \
|
11
|
+
whereas 'parallel' needs predefined lambdas"
|
12
|
+
s.author = "Ralf Mueller"
|
13
|
+
s.email = "stark.dreamdetective@gmail.com"
|
14
|
+
s.homepage = "https://github.com/Try2Code/jobQueue"
|
15
|
+
s.extra_rdoc_files = ["README.rdoc","LICENSE"]
|
16
|
+
s.license = "ISC" #BSD-2-Clause
|
17
|
+
s.test_file = "test/test_parallelQueue.rb"
|
18
|
+
s.required_ruby_version = ">= 1.8"
|
19
|
+
s.has_rdoc = true
|
20
|
+
end
|
21
|
+
|
22
|
+
# vim:ft=ruby
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'parallel'
|
2
|
+
# ==============================================================================
|
3
|
+
# Author: Ralf Mueller, ralf.mueller@mpimet.mpg.de
|
4
|
+
# suggestions from Robert Klemme (https://www.ruby-forum.com/topic/68001#86298)
|
5
|
+
#
|
6
|
+
# ==============================================================================
|
7
|
+
|
8
|
+
# ParallelQueue is nothing but a regular queue with the ability to store blocks
|
9
|
+
# or methods (plus aruments)
|
10
|
+
class ParallelQueue < Queue
|
11
|
+
alias :queue_push :push
|
12
|
+
include Parallel::ProcessorCount
|
13
|
+
|
14
|
+
# puts code to the queue as a
|
15
|
+
# * method: push(method,arg1,arg2,...)
|
16
|
+
# * block: push { ... }
|
17
|
+
def push (*item, &block)
|
18
|
+
queue_push(item ) unless item.empty?
|
19
|
+
queue_push([block]) unless block.nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
# run things with the 'parallel' library - results are returned automatically
|
23
|
+
def run(workers=processor_count)
|
24
|
+
queue_push(Parallel::Stop)
|
25
|
+
Parallel.map(self,:in_threads => workers) {|task|
|
26
|
+
if task.size > 1
|
27
|
+
if task[0].kind_of? Proc
|
28
|
+
# Expects proc/lambda with arguments,e.g.
|
29
|
+
# [mysqrt,2.789]
|
30
|
+
# [myproc,x,y,z]
|
31
|
+
task[0].call(*task[1..-1])
|
32
|
+
else
|
33
|
+
# expect an object in task[0] and one of its methods with arguments
|
34
|
+
# in task[1] as a symbol
|
35
|
+
# e.g. [a,[:attribute=,1] or
|
36
|
+
# Math,:exp,0
|
37
|
+
task[0].send(task[1],*task[2..-1])
|
38
|
+
end
|
39
|
+
else
|
40
|
+
task[0].call
|
41
|
+
end
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
# run the given calls WITHOUT automatic result storage, but faster
|
46
|
+
def justRun(workers=processor_count)
|
47
|
+
@threads = (1..workers).map {|i|
|
48
|
+
Thread.new(self) {|q|
|
49
|
+
until ( q == ( task = q.deq ) )
|
50
|
+
if task.size > 1
|
51
|
+
if task[0].kind_of? Proc
|
52
|
+
# Expects proc/lambda with arguments, e.g. [mysqrt,2.789]
|
53
|
+
task[0].call(*task[1..-1])
|
54
|
+
else
|
55
|
+
# expect an object in task[0] and one of its methods with
|
56
|
+
# arguments in task[1] as a symbol
|
57
|
+
# e.g. [a,[:attribute=,1]
|
58
|
+
task[0].send(task[1],*task[2..-1])
|
59
|
+
end
|
60
|
+
else
|
61
|
+
task[0].call
|
62
|
+
end
|
63
|
+
end
|
64
|
+
}
|
65
|
+
}
|
66
|
+
@threads.size.times { self.enq self}
|
67
|
+
@threads.each {|t| t.join}
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'parallel'
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__),"..","lib")
|
4
|
+
require 'parallelQueue'
|
5
|
+
|
6
|
+
class TestParallelQueue < Minitest::Test
|
7
|
+
|
8
|
+
def test_blocks
|
9
|
+
q = ParallelQueue.new
|
10
|
+
|
11
|
+
itemsA = %w[a:3:b x:55:x K:981:foo:tra]
|
12
|
+
itemsB = %w[a|5|b x|11|x K|187|foo|tra]
|
13
|
+
|
14
|
+
itemsA.each {|item|
|
15
|
+
q.push {
|
16
|
+
item.split(':')[1].to_i
|
17
|
+
}
|
18
|
+
}
|
19
|
+
itemsB.each {|item|
|
20
|
+
q.push {
|
21
|
+
item.split('|')[1].to_i
|
22
|
+
}
|
23
|
+
}
|
24
|
+
results = q.run.sort
|
25
|
+
assert_equal([3,5,11,55,187,981],results)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_procs
|
29
|
+
q = ParallelQueue.new
|
30
|
+
|
31
|
+
myProc = lambda {|r| Math.sqrt(r)}
|
32
|
+
pressure = lambda {|z|
|
33
|
+
1013.25*Math.exp((-1)*(1.602769777072154)*Math.log((Math.exp(z/10000.0)*213.15+75.0)/288.15))
|
34
|
+
}
|
35
|
+
temperature = lambda {|z|
|
36
|
+
213.0+75.0*Math.exp((-1)*z/10000.0)-273.15
|
37
|
+
}
|
38
|
+
vectorLength = lambda {|x,y,z| Math.sqrt(x*x + y*y + z*z) }
|
39
|
+
|
40
|
+
q.push(myProc,4.0)
|
41
|
+
q.push(Math,:sqrt,16.0)
|
42
|
+
[0,10,20,50,100,200,500,1000].map(&:to_f).each {|z|
|
43
|
+
q.push(pressure,z)
|
44
|
+
q.push(temperature,z)
|
45
|
+
}
|
46
|
+
q.push(Math,:sqrt,529.0)
|
47
|
+
q.push(vectorLength,0,1,0)
|
48
|
+
q.push(vectorLength,0,1,1)
|
49
|
+
q.push(vectorLength,1,1,1)
|
50
|
+
|
51
|
+
results = q.run(2).map {|f| f.round(2)}
|
52
|
+
assert_equal(
|
53
|
+
[1.0,1.41,1.73,2.0, 4.0, 7.71, 11.19, 13.36, 14.1, 14.48, 14.7, 14.78, 14.85, 23.0, 898.6, 954.56, 989.45, 1001.29, 1007.26, 1010.85, 1012.05, 1013.25],
|
54
|
+
results.sort
|
55
|
+
)
|
56
|
+
end
|
57
|
+
end
|
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: parallelQueue
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ralf Mueller
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-02-29 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: 'Extension ''parallel'': Interface for pushung blocks'
|
14
|
+
email: stark.dreamdetective@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files:
|
18
|
+
- README.rdoc
|
19
|
+
- LICENSE
|
20
|
+
files:
|
21
|
+
- LICENSE
|
22
|
+
- README.rdoc
|
23
|
+
- gemspec.parallelQueue
|
24
|
+
- lib/parallelQueue.rb
|
25
|
+
- test/test_parallelQueue.rb
|
26
|
+
homepage: https://github.com/Try2Code/jobQueue
|
27
|
+
licenses:
|
28
|
+
- ISC
|
29
|
+
metadata: {}
|
30
|
+
post_install_message:
|
31
|
+
rdoc_options: []
|
32
|
+
require_paths:
|
33
|
+
- lib
|
34
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - ">="
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '1.8'
|
39
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
requirements: []
|
45
|
+
rubyforge_project:
|
46
|
+
rubygems_version: 2.5.1
|
47
|
+
signing_key:
|
48
|
+
specification_version: 4
|
49
|
+
summary: This is a small extension to the 'parallel' library. It allows
|
50
|
+
to push abitrary blocks to a Queue and execute them in parallel, whereas
|
51
|
+
'parallel' needs predefined lambdas
|
52
|
+
test_files:
|
53
|
+
- test/test_parallelQueue.rb
|