From 4ed80d2a4719e080d320c41bbfab54061f7e8fbe Mon Sep 17 00:00:00 2001 From: Chris Cadden Date: Thu, 22 Feb 2024 22:04:42 -0500 Subject: [PATCH 1/8] bin/configlet create --practice-exercise parallel-letter-frequency --- config.json | 8 +++ .../.docs/instructions.md | 7 +++ .../.meta/config.json | 15 ++++++ .../.meta/example.rb | 0 .../.meta/tests.toml | 49 +++++++++++++++++++ .../parallel_letter_frequency.rb | 0 .../parallel_letter_frequency_test.rb | 0 7 files changed, 79 insertions(+) create mode 100644 exercises/practice/parallel-letter-frequency/.docs/instructions.md create mode 100644 exercises/practice/parallel-letter-frequency/.meta/config.json create mode 100644 exercises/practice/parallel-letter-frequency/.meta/example.rb create mode 100644 exercises/practice/parallel-letter-frequency/.meta/tests.toml create mode 100644 exercises/practice/parallel-letter-frequency/parallel_letter_frequency.rb create mode 100644 exercises/practice/parallel-letter-frequency/parallel_letter_frequency_test.rb diff --git a/config.json b/config.json index b1608fc58c..6d50b562b5 100644 --- a/config.json +++ b/config.json @@ -1547,6 +1547,14 @@ "enumeration" ], "difficulty": 8 + }, + { + "slug": "parallel-letter-frequency", + "name": "Parallel Letter Frequency", + "uuid": "527fdec4-a24e-491d-8f2d-7496054b6e88", + "practices": [], + "prerequisites": [], + "difficulty": 1 } ] }, diff --git a/exercises/practice/parallel-letter-frequency/.docs/instructions.md b/exercises/practice/parallel-letter-frequency/.docs/instructions.md new file mode 100644 index 0000000000..85abcf86a4 --- /dev/null +++ b/exercises/practice/parallel-letter-frequency/.docs/instructions.md @@ -0,0 +1,7 @@ +# Instructions + +Count the frequency of letters in texts using parallel computation. + +Parallelism is about doing things in parallel that can also be done sequentially. +A common example is counting the frequency of letters. +Create a function that returns the total frequency of each letter in a list of texts and that employs parallelism. diff --git a/exercises/practice/parallel-letter-frequency/.meta/config.json b/exercises/practice/parallel-letter-frequency/.meta/config.json new file mode 100644 index 0000000000..233312dbc1 --- /dev/null +++ b/exercises/practice/parallel-letter-frequency/.meta/config.json @@ -0,0 +1,15 @@ +{ + "authors": [], + "files": { + "solution": [ + "parallel_letter_frequency.rb" + ], + "test": [ + "parallel_letter_frequency_test.rb" + ], + "example": [ + ".meta/example.rb" + ] + }, + "blurb": "Count the frequency of letters in texts using parallel computation." +} diff --git a/exercises/practice/parallel-letter-frequency/.meta/example.rb b/exercises/practice/parallel-letter-frequency/.meta/example.rb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/exercises/practice/parallel-letter-frequency/.meta/tests.toml b/exercises/practice/parallel-letter-frequency/.meta/tests.toml new file mode 100644 index 0000000000..0c974f7fd7 --- /dev/null +++ b/exercises/practice/parallel-letter-frequency/.meta/tests.toml @@ -0,0 +1,49 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[c054d642-c1fa-4234-8007-9339f2337886] +description = "no texts" + +[818031be-49dc-4675-b2f9-c4047f638a2a] +description = "one text with one letter" + +[c0b81d1b-940d-4cea-9f49-8445c69c17ae] +description = "one text with multiple letters" + +[708ff1e0-f14a-43fd-adb5-e76750dcf108] +description = "two texts with one letter" + +[1b5c28bb-4619-4c9d-8db9-a4bb9c3bdca0] +description = "two texts with multiple letters" + +[6366e2b8-b84c-4334-a047-03a00a656d63] +description = "ignore letter casing" + +[92ebcbb0-9181-4421-a784-f6f5aa79f75b] +description = "ignore whitespace" + +[bc5f4203-00ce-4acc-a5fa-f7b865376fd9] +description = "ignore punctuation" + +[68032b8b-346b-4389-a380-e397618f6831] +description = "ignore numbers" + +[aa9f97ac-3961-4af1-88e7-6efed1bfddfd] +description = "Unicode letters" + +[7b1da046-701b-41fc-813e-dcfb5ee51813] +description = "combination of lower- and uppercase letters, punctuation and white space" + +[4727f020-df62-4dcf-99b2-a6e58319cb4f] +description = "large texts" + +[adf8e57b-8e54-4483-b6b8-8b32c115884c] +description = "many small texts" diff --git a/exercises/practice/parallel-letter-frequency/parallel_letter_frequency.rb b/exercises/practice/parallel-letter-frequency/parallel_letter_frequency.rb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/exercises/practice/parallel-letter-frequency/parallel_letter_frequency_test.rb b/exercises/practice/parallel-letter-frequency/parallel_letter_frequency_test.rb new file mode 100644 index 0000000000..e69de29bb2 From c2c600984bd4d29475d66fde601545770d7d243d Mon Sep 17 00:00:00 2001 From: Chris Cadden Date: Thu, 22 Feb 2024 22:05:59 -0500 Subject: [PATCH 2/8] Add parallel-letter-frequency difficulty --- config.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/config.json b/config.json index 6d50b562b5..3e21797c0a 100644 --- a/config.json +++ b/config.json @@ -765,6 +765,14 @@ ], "difficulty": 6 }, + { + "slug": "parallel-letter-frequency", + "name": "Parallel Letter Frequency", + "uuid": "527fdec4-a24e-491d-8f2d-7496054b6e88", + "practices": [], + "prerequisites": [], + "difficulty": 6 + }, { "slug": "accumulate", "name": "Accumulate", @@ -1547,14 +1555,6 @@ "enumeration" ], "difficulty": 8 - }, - { - "slug": "parallel-letter-frequency", - "name": "Parallel Letter Frequency", - "uuid": "527fdec4-a24e-491d-8f2d-7496054b6e88", - "practices": [], - "prerequisites": [], - "difficulty": 1 } ] }, From 543913d9e69cbe8078871cf40f183e1b91e239e7 Mon Sep 17 00:00:00 2001 From: Chris Cadden Date: Thu, 22 Feb 2024 22:07:28 -0500 Subject: [PATCH 3/8] Add parallel_letter_frequency.rb stub file --- .../parallel-letter-frequency/parallel_letter_frequency.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/exercises/practice/parallel-letter-frequency/parallel_letter_frequency.rb b/exercises/practice/parallel-letter-frequency/parallel_letter_frequency.rb index e69de29bb2..18abc3db41 100644 --- a/exercises/practice/parallel-letter-frequency/parallel_letter_frequency.rb +++ b/exercises/practice/parallel-letter-frequency/parallel_letter_frequency.rb @@ -0,0 +1,6 @@ +=begin +Write your code for the 'Parallel Letter Frequency' exercise in this file. Make the tests in +`parallel_letter_frequency_test.rb` pass. +To get started with TDD, see the `README.md` file in your +`ruby/parallel_letter_frequency` directory. +=end From f76c74d97769f6e3f9656f600acd7ab94265de5e Mon Sep 17 00:00:00 2001 From: Chris Cadden Date: Thu, 22 Feb 2024 23:34:08 -0500 Subject: [PATCH 4/8] Include instructions.append.md with parallelism/concurrency resources --- .../parallel-letter-frequency/.docs/instructions.append.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 exercises/practice/parallel-letter-frequency/.docs/instructions.append.md diff --git a/exercises/practice/parallel-letter-frequency/.docs/instructions.append.md b/exercises/practice/parallel-letter-frequency/.docs/instructions.append.md new file mode 100644 index 0000000000..67e82194ee --- /dev/null +++ b/exercises/practice/parallel-letter-frequency/.docs/instructions.append.md @@ -0,0 +1,7 @@ +# Instructions Append +## Further Reading + +- [Ruby `Thread` Documentation](https://docs.ruby-lang.org/en/master/Thread.html) +- [Ruby `Thread::Queue` Documentation](https://docs.ruby-lang.org/en/master/Thread/Queue.html) +- [Ruby `Fiber` Documentation](https://docs.ruby-lang.org/en/master/Fiber.html) +- [Ruby `Ractor` Documentation](https://docs.ruby-lang.org/en/master/Ractor.html) From 973aa63bc9be6e209ee0b84e0a91b755278ac31d Mon Sep 17 00:00:00 2001 From: Chris Cadden Date: Thu, 22 Feb 2024 23:33:18 -0500 Subject: [PATCH 5/8] Add parallel_letter_frequency_test.rb Co-authored-by: KOTP --- .../data/moby_dick_ch37.txt | 9 + .../data/moby_dick_ch38.txt | 7 + .../data/moby_dick_ch39.txt | 12 ++ .../data/ruby_wiki.txt | 3 + .../parallel_letter_frequency_test.rb | 194 ++++++++++++++++++ 5 files changed, 225 insertions(+) create mode 100644 exercises/practice/parallel-letter-frequency/data/moby_dick_ch37.txt create mode 100644 exercises/practice/parallel-letter-frequency/data/moby_dick_ch38.txt create mode 100644 exercises/practice/parallel-letter-frequency/data/moby_dick_ch39.txt create mode 100644 exercises/practice/parallel-letter-frequency/data/ruby_wiki.txt diff --git a/exercises/practice/parallel-letter-frequency/data/moby_dick_ch37.txt b/exercises/practice/parallel-letter-frequency/data/moby_dick_ch37.txt new file mode 100644 index 0000000000..d818696e1a --- /dev/null +++ b/exercises/practice/parallel-letter-frequency/data/moby_dick_ch37.txt @@ -0,0 +1,9 @@ + The cabin; by the stern windows; Ahab sitting alone, and gazing out. + +I leave a white and turbid wake; pale waters, paler cheeks, where’er I sail. The envious billows sidelong swell to whelm my track; let them; but first I pass. + +Yonder, by ever-brimming goblet’s rim, the warm waves blush like wine. The gold brow plumbs the blue. The diver sun—slow dived from noon—goes down; my soul mounts up! she wearies with her endless hill. Is, then, the crown too heavy that I wear? this Iron Crown of Lombardy. Yet is it bright with many a gem; I the wearer, see not its far flashings; but darkly feel that I wear that, that dazzlingly confounds. ’Tis iron—that I know—not gold. ’Tis split, too—that I feel; the jagged edge galls me so, my brain seems to beat against the solid metal; aye, steel skull, mine; the sort that needs no helmet in the most brain-battering fight! + +Dry heat upon my brow? Oh! time was, when as the sunrise nobly spurred me, so the sunset soothed. No more. This lovely light, it lights not me; all loveliness is anguish to me, since I can ne’er enjoy. Gifted with the high perception, I lack the low, enjoying power; damned, most subtly and most malignantly! damned in the midst of Paradise! Good night—good night! (waving his hand, he moves from the window.) + +’Twas not so hard a task. I thought to find one stubborn, at the least; but my one cogged circle fits into all their various wheels, and they revolve. Or, if you will, like so many ant-hills of powder, they all stand before me; and I their match. Oh, hard! that to fire others, the match itself must needs be wasting! What I’ve dared, I’ve willed; and what I’ve willed, I’ll do! They think me mad—Starbuck does; but I’m demoniac, I am madness maddened! That wild madness that’s only calm to comprehend itself! The prophecy was that I should be dismembered; and—Aye! I lost this leg. I now prophesy that I will dismember my dismemberer. Now, then, be the prophet and the fulfiller one. That’s more than ye, ye great gods, ever were. I laugh and hoot at ye, ye cricket-players, ye pugilists, ye deaf Burkes and blinded Bendigoes! I will not say as schoolboys do to bullies—Take some one of your own size; don’t pommel me! No, ye’ve knocked me down, and I am up again; but ye have run and hidden. Come forth from behind your cotton bags! I have no long gun to reach ye. Come, Ahab’s compliments to ye; come and see if ye can swerve me. Swerve me? ye cannot swerve me, else ye swerve yourselves! man has ye there. Swerve me? The path to my fixed purpose is laid with iron rails, whereon my soul is grooved to run. Over unsounded gorges, through the rifled hearts of mountains, under torrents’ beds, unerringly I rush! Naught’s an obstacle, naught’s an angle to the iron way! diff --git a/exercises/practice/parallel-letter-frequency/data/moby_dick_ch38.txt b/exercises/practice/parallel-letter-frequency/data/moby_dick_ch38.txt new file mode 100644 index 0000000000..84969c2aad --- /dev/null +++ b/exercises/practice/parallel-letter-frequency/data/moby_dick_ch38.txt @@ -0,0 +1,7 @@ + By the Mainmast; Starbuck leaning against it. + +My soul is more than matched; she’s overmanned; and by a madman! Insufferable sting, that sanity should ground arms on such a field! But he drilled deep down, and blasted all my reason out of me! I think I see his impious end; but feel that I must help him to it. Will I, nill I, the ineffable thing has tied me to him; tows me with a cable I have no knife to cut. Horrible old man! Who’s over him, he cries;—aye, he would be a democrat to all above; look, how he lords it over all below! Oh! I plainly see my miserable office,—to obey, rebelling; and worse yet, to hate with touch of pity! For in his eyes I read some lurid woe would shrivel me up, had I it. Yet is there hope. Time and tide flow wide. The hated whale has the round watery world to swim in, as the small gold-fish has its glassy globe. His heaven-insulting purpose, God may wedge aside. I would up heart, were it not like lead. But my whole clock’s run down; my heart the all-controlling weight, I have no key to lift again. + +[A burst of revelry from the forecastle.] + +Oh, God! to sail with such a heathen crew that have small touch of human mothers in them! Whelped somewhere by the sharkish sea. The white whale is their demigorgon. Hark! the infernal orgies! that revelry is forward! mark the unfaltering silence aft! Methinks it pictures life. Foremost through the sparkling sea shoots on the gay, embattled, bantering bow, but only to drag dark Ahab after it, where he broods within his sternward cabin, builded over the dead water of the wake, and further on, hunted by its wolfish gurglings. The long howl thrills me through! Peace! ye revellers, and set the watch! Oh, life! ’tis in an hour like this, with soul beat down and held to knowledge,—as wild, untutored things are forced to feed—Oh, life! ’tis now that I do feel the latent horror in thee! but ’tis not me! that horror’s out of me! and with the soft feeling of the human in me, yet will I try to fight ye, ye grim, phantom futures! Stand by me, hold me, bind me, O ye blessed influences! diff --git a/exercises/practice/parallel-letter-frequency/data/moby_dick_ch39.txt b/exercises/practice/parallel-letter-frequency/data/moby_dick_ch39.txt new file mode 100644 index 0000000000..cf24d40281 --- /dev/null +++ b/exercises/practice/parallel-letter-frequency/data/moby_dick_ch39.txt @@ -0,0 +1,12 @@ + Fore-Top. + +(Stubb solus, and mending a brace.) + +Ha! ha! ha! ha! hem! clear my throat!—I’ve been thinking over it ever since, and that ha, ha’s the final consequence. Why so? Because a laugh’s the wisest, easiest answer to all that’s queer; and come what will, one comfort’s always left—that unfailing comfort is, it’s all predestinated. I heard not all his talk with Starbuck; but to my poor eye Starbuck then looked something as I the other evening felt. Be sure the old Mogul has fixed him, too. I twigged it, knew it; had had the gift, might readily have prophesied it—for when I clapped my eye upon his skull I saw it. Well, Stubb, wise Stubb—that’s my title—well, Stubb, what of it, Stubb? Here’s a carcase. I know not all that may be coming, but be it what it will, I’ll go to it laughing. Such a waggish leering as lurks in all your horribles! I feel funny. Fa, la! lirra, skirra! What’s my juicy little pear at home doing now? Crying its eyes out?—Giving a party to the last arrived harpooneers, I dare say, gay as a frigate’s pennant, and so am I—fa, la! lirra, skirra! Oh— + + We’ll drink to-night with hearts as light, + To love, as gay and fleeting + As bubbles that swim, on the beaker’s brim, + And break on the lips while meeting. + +A brave stave that—who calls? Mr. Starbuck? Aye, aye, sir—(Aside) he’s my superior, he has his too, if I’m not mistaken.—Aye, aye, sir, just through with this job—coming. diff --git a/exercises/practice/parallel-letter-frequency/data/ruby_wiki.txt b/exercises/practice/parallel-letter-frequency/data/ruby_wiki.txt new file mode 100644 index 0000000000..f9cfff1e9d --- /dev/null +++ b/exercises/practice/parallel-letter-frequency/data/ruby_wiki.txt @@ -0,0 +1,3 @@ +Ruby is an interpreted, high-level, general-purpose programming language which supports multiple programming paradigms. It was designed with an emphasis on programming productivity and simplicity. In Ruby, everything is an object, including primitive data types. It was developed in the mid-1990s by Yukihiro "Matz" Matsumoto in Japan. + +Ruby is dynamically typed and uses garbage collection and just-in-time compilation. It supports multiple programming paradigms, including procedural, object-oriented, and functional programming. According to the creator, Ruby was influenced by Perl, Smalltalk, Eiffel, Ada, BASIC, Java, and Lisp. diff --git a/exercises/practice/parallel-letter-frequency/parallel_letter_frequency_test.rb b/exercises/practice/parallel-letter-frequency/parallel_letter_frequency_test.rb index e69de29bb2..1ca5a99241 100644 --- a/exercises/practice/parallel-letter-frequency/parallel_letter_frequency_test.rb +++ b/exercises/practice/parallel-letter-frequency/parallel_letter_frequency_test.rb @@ -0,0 +1,194 @@ +require 'minitest/autorun' +require_relative 'parallel_letter_frequency' + +# rubocop:disable Layout/SpaceInsideHashLiteralBraces +class ParallelLetterFrequencyTest < Minitest::Test + def test_no_texts + # skip + texts = %w[] + expected = {} + actual = ParallelLetterFrequency.count(texts) + assert_equal expected, actual + end + + def test_one_text_one_letter + skip + texts = %w[a] + expected = {'a' => 1} + actual = ParallelLetterFrequency.count(texts) + assert_equal expected, actual + end + + def test_one_text_multiple_letters + skip + texts = %w[abbca] + expected = {'a' => 2, 'b' => 2, 'c' => 1} + actual = ParallelLetterFrequency.count(texts) + assert_equal expected, actual + end + + def test_two_texts_one_letter + skip + texts = %w[a a] + expected = {'a' => 2} + actual = ParallelLetterFrequency.count(texts) + assert_equal expected, actual + end + + def test_two_texts_multiple_letters + skip + texts = %w[abcd ac] + expected = {'a' => 2, 'b' => 1, 'c' => 2, 'd' => 1} + actual = ParallelLetterFrequency.count(texts) + assert_equal expected, actual + end + + def test_ignore_letter_case + skip + texts = %w[Aa aA] + expected = {'a' => 4} + actual = ParallelLetterFrequency.count(texts) + assert_equal expected, actual + end + + def test_ignore_whitespace + skip + texts = [' ', "\t", "\n", "\r\n"] + expected = {} + actual = ParallelLetterFrequency.count(texts) + assert_equal expected, actual + end + + def test_ignore_punctuation + skip + texts = ['!', '?', ';', ',', '.', '-', "'", '"', '/', ':', '{}', '[]', '()'] + expected = {} + actual = ParallelLetterFrequency.count(texts) + assert_equal expected, actual + end + + def test_ignore_numbers + skip + texts = %w[1 2 3 4 5 6 7 8 9 0] + expected = {} + actual = ParallelLetterFrequency.count(texts) + assert_equal expected, actual + end + + def test_unicode_letters + skip + texts = %w[本 φ ほ ø] + expected = {'本' => 1, 'φ' => 1, 'ほ' => 1, 'ø' => 1} + actual = ParallelLetterFrequency.count(texts) + assert_equal expected, actual + end + + def test_combo_lower_upper_punctuation_whitespace + skip + ruby_wiki = File.read(File.expand_path('data/ruby_wiki.txt', __dir__)) + texts = ruby_wiki + expected = { + "r" => 34, + "u" => 20, + "b" => 10, + "y" => 14, + "i" => 53, + "s" => 26, + "a" => 46, + "n" => 37, + "t" => 34, + "e" => 39, + "p" => 28, + "d" => 24, + "h" => 10, + "g" => 23, + "l" => 26, + "v" => 6, + "o" => 26, + "m" => 25, + "w" => 5, + "c" => 18, + "j" => 5, + "k" => 2, + "z" => 1, + "f" => 4 + } + actual = ParallelLetterFrequency.count(texts) + assert_equal expected, actual + end + + def test_large_texts + skip + ch37 = File.read(File.expand_path('data/moby_dick_ch37.txt', __dir__)) + ch38 = File.read(File.expand_path('data/moby_dick_ch38.txt', __dir__)) + ch39 = File.read(File.expand_path('data/moby_dick_ch39.txt', __dir__)) + texts = [ch37, ch38, ch39] + expected = { + "f" => 89, + "o" => 333, + "r" => 250, + "e" => 570, + "t" => 429, + "p" => 57, + "s" => 311, + "u" => 131, + "b" => 110, + "l" => 260, + "a" => 356, + "n" => 278, + "d" => 184, + "m" => 156, + "i" => 352, + "g" => 120, + "c" => 77, + "h" => 308, + "y" => 113, + "v" => 52, + "k" => 49, + "q" => 2, + "w" => 133, + "x" => 2, + "j" => 6, + "z" => 4 + } + actual = ParallelLetterFrequency.count(texts) + assert_equal expected, actual + end + + def test_many_small_texts + skip + texts = Array.new(100, 'abc') + actual = ParallelLetterFrequency.count(texts) + expected = {'a' => 100, 'b' => 100, 'c' => 100} + assert_equal expected, actual + end + + def test_faster_than_serialized_answer + skip + texts = Array.new(20, 'a' * 100_000) + + GC.start + t0_parallel = Minitest.clock_time + ParallelLetterFrequency.count(texts) + parallel_time = Minitest.clock_time - t0_parallel + + t0_sequential = Minitest.clock_time + sequential_letter_frequency(texts) + sequential_time = Minitest.clock_time - t0_sequential + + assert parallel_time < sequential_time, + 'Parallel execution should be faster than sequential for batches of large texts' + end + + def sequential_letter_frequency(texts) + tally = Hash.new(0) + texts.each do |text| + text.each_grapheme_cluster do |cluster| + tally[cluster] += 1 + end + end + + tally + end +end +# rubocop:enable Layout/SpaceInsideHashLiteralBraces From 9e83dda5ea37a3c62de9bb6020320a738bd1dec4 Mon Sep 17 00:00:00 2001 From: Chris Cadden Date: Sun, 25 Feb 2024 13:26:48 -0500 Subject: [PATCH 6/8] Add Minitest benchmarking file for sequential vs parallel execution Co-authored-by: KOTP --- .../.docs/instructions.append.md | 12 ++++++ ...arallel_letter_frequency_benchmark_test.rb | 39 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 exercises/practice/parallel-letter-frequency/parallel_letter_frequency_benchmark_test.rb diff --git a/exercises/practice/parallel-letter-frequency/.docs/instructions.append.md b/exercises/practice/parallel-letter-frequency/.docs/instructions.append.md index 67e82194ee..28798a1cf2 100644 --- a/exercises/practice/parallel-letter-frequency/.docs/instructions.append.md +++ b/exercises/practice/parallel-letter-frequency/.docs/instructions.append.md @@ -1,7 +1,19 @@ # Instructions Append + +## Benchmarking + +If you are solving this exercise locally, there is an included `parallel_letter_frequency_benchmark_test.rb` file which will compare your parallel solution to a sequential one. +You can run it via `ruby parallel_letter_frequency_benchmark_test.rb`. +The output will show execution times of each implementation over a range of large text counts in a tabular format. +Feel free to change the test cases. +You may want to investigate what performance impact length of text vs number of texts has on the execution time for each implementation. + +**Note:** For smaller sets of text, the sequential count _may_ be faster due to processing overhead costs. + ## Further Reading - [Ruby `Thread` Documentation](https://docs.ruby-lang.org/en/master/Thread.html) - [Ruby `Thread::Queue` Documentation](https://docs.ruby-lang.org/en/master/Thread/Queue.html) - [Ruby `Fiber` Documentation](https://docs.ruby-lang.org/en/master/Fiber.html) - [Ruby `Ractor` Documentation](https://docs.ruby-lang.org/en/master/Ractor.html) +- [`Minitest::Benchmark` Documentation](https://ruby-doc.org/3.0.6/gems/minitest/Minitest/Benchmark.html) diff --git a/exercises/practice/parallel-letter-frequency/parallel_letter_frequency_benchmark_test.rb b/exercises/practice/parallel-letter-frequency/parallel_letter_frequency_benchmark_test.rb new file mode 100644 index 0000000000..025fcd973a --- /dev/null +++ b/exercises/practice/parallel-letter-frequency/parallel_letter_frequency_benchmark_test.rb @@ -0,0 +1,39 @@ +require 'minitest/autorun' +require 'minitest/benchmark' +require_relative 'parallel_letter_frequency' + +class ParallelLetterFrequencyBenchmarkTest < Minitest::Benchmark + def self.bench_range + bench_exp(1, 100_000) + end + + def setup + @strings = {} + self.class.bench_range.each do |n| + @strings[n] = Array.new(10, 'a' * n) + end + end + + def bench_sequential + assert_performance ->(_, _) { true } do |n| + sequential_letter_frequency(@strings[n]) + end + end + + def bench_parallel + assert_performance ->(_, _) { true } do |n| + ParallelLetterFrequency.count(@strings[n]) + end + end + + def sequential_letter_frequency(texts) + tally = Hash.new(0) + texts.each do |text| + text.each_grapheme_cluster do |cluster| + tally[cluster] += 1 + end + end + + tally + end +end From 3e072978a891526ae7a2765f1055ca3a6e513a1a Mon Sep 17 00:00:00 2001 From: Chris Cadden Date: Thu, 22 Feb 2024 23:33:41 -0500 Subject: [PATCH 7/8] Add example implementation of parallel_letter_frequency exercise Co-authored-by: KOTP --- .../.meta/example.rb | 23 +++++++++++++++++++ .../parallel_letter_frequency.rb | 11 +++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/exercises/practice/parallel-letter-frequency/.meta/example.rb b/exercises/practice/parallel-letter-frequency/.meta/example.rb index e69de29bb2..2c3039eb77 100644 --- a/exercises/practice/parallel-letter-frequency/.meta/example.rb +++ b/exercises/practice/parallel-letter-frequency/.meta/example.rb @@ -0,0 +1,23 @@ +class ParallelLetterFrequency + def self.count(texts) + ractors = (0...texts.length).map do |i| + Ractor.new(texts[i]) do |text| + text.downcase.each_grapheme_cluster.select do |cluster| + cluster.match?(/\p{Alpha}/) + end.tally + end + end + + tally = Hash.new(0) + + until ractors.empty? + ractor, result = Ractor.select(*ractors) + ractors.delete ractor + result.each do |key, value| + tally[key] += value + end + end + + tally + end +end diff --git a/exercises/practice/parallel-letter-frequency/parallel_letter_frequency.rb b/exercises/practice/parallel-letter-frequency/parallel_letter_frequency.rb index 18abc3db41..ab0816559d 100644 --- a/exercises/practice/parallel-letter-frequency/parallel_letter_frequency.rb +++ b/exercises/practice/parallel-letter-frequency/parallel_letter_frequency.rb @@ -1,6 +1,7 @@ -=begin -Write your code for the 'Parallel Letter Frequency' exercise in this file. Make the tests in -`parallel_letter_frequency_test.rb` pass. -To get started with TDD, see the `README.md` file in your -`ruby/parallel_letter_frequency` directory. +=begin +Write your code for the 'Parallel Letter Frequency' exercise in this file. Make +the tests in `parallel_letter_frequency_test.rb` pass. + +To get started with TDD, see the `README.md` file in your +`ruby/parallel_letter_frequency` directory. =end From 268ea0a770ed8397959e1e6d1fe5cfdce4804fad Mon Sep 17 00:00:00 2001 From: Chris Cadden Date: Thu, 22 Feb 2024 23:36:45 -0500 Subject: [PATCH 8/8] Add authors --- .../parallel-letter-frequency/.meta/config.json | 5 ++++- .../parallel_letter_frequency.rb | 12 ++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/exercises/practice/parallel-letter-frequency/.meta/config.json b/exercises/practice/parallel-letter-frequency/.meta/config.json index 233312dbc1..82f9091538 100644 --- a/exercises/practice/parallel-letter-frequency/.meta/config.json +++ b/exercises/practice/parallel-letter-frequency/.meta/config.json @@ -1,5 +1,8 @@ { - "authors": [], + "authors": [ + "mr-sigma", + "kotp" + ], "files": { "solution": [ "parallel_letter_frequency.rb" diff --git a/exercises/practice/parallel-letter-frequency/parallel_letter_frequency.rb b/exercises/practice/parallel-letter-frequency/parallel_letter_frequency.rb index ab0816559d..8c8f795e88 100644 --- a/exercises/practice/parallel-letter-frequency/parallel_letter_frequency.rb +++ b/exercises/practice/parallel-letter-frequency/parallel_letter_frequency.rb @@ -1,7 +1,7 @@ -=begin -Write your code for the 'Parallel Letter Frequency' exercise in this file. Make -the tests in `parallel_letter_frequency_test.rb` pass. - -To get started with TDD, see the `README.md` file in your -`ruby/parallel_letter_frequency` directory. +=begin +Write your code for the 'Parallel Letter Frequency' exercise in this file. Make +the tests in `parallel_letter_frequency_test.rb` pass. + +To get started with TDD, see the `README.md` file in your +`ruby/parallel_letter_frequency` directory. =end