-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMain.cs
More file actions
274 lines (232 loc) · 9.88 KB
/
Main.cs
File metadata and controls
274 lines (232 loc) · 9.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Bridge;
using Bridge.Html5;
using Bridge.Linq;
namespace Threading
{
public class Main
{
// The range of numbers to test for primes (0 - n)
private const int MaxNumber = 10000000;
// If the first 1000 primes from each run should be printed
private const bool PrintFirst1000Primes = false;
// The list of ints representing the number of threads to execute in each run
private static readonly List<int> NumberOfThreadsPerTest = new List<int> {1, 2, 4, 6, 8, 12, 16};
// Used to pass the range of ints to the RunPrime thread
[ObjectLiteral]
private class PrimeRange
{
// The first int in the range
public int First;
// The last int in the range
public int Last;
}
// Checks if a single number is prime
private static bool IsPrime(int number)
{
if (number == 1) return false;
if (number == 2) return true;
var boundary = (int) Math.Floor(Math.Sqrt(number));
for (var i = 2; i <= boundary; ++i)
{
if (number % i == 0) return false;
}
return true;
}
// The entry point of each thread
private static object RunPrime(object param)
{
// Convert the parameter to a range object
var range = param as PrimeRange;
// Create an array to store the list of prime numbers found in the range
var primes = new List<int>();
// Iterate over the range and add any prime numbers to the primes array
for (var n = range.First; n < range.Last; n++)
{
// Check if this number is prime
if (IsPrime(n))
// Yes, add the number to the array
primes.Add(n);
}
// Return the prime numbers
return primes.ToArray();
}
// Need to add a thread pool to Bridge perhaps
// Simple utility function to join all threads in an array.
private static void JoinAll(IEnumerable<Thread> threads, Action onJoined)
{
// Check if any threads are still alive
if (threads.Any(e => e.IsAlive))
// Yes, check again in a few milliseconds
Window.SetTimeout(() => JoinAll(threads, onJoined), 10);
else
// No, all threads are finished, trigger the callback
onJoined();
}
// Runs the next primes benchmark
private static void BenchmarkPrimes()
{
// Get the number of threads for this benchmark
var numberOfThreads = NumberOfThreadsPerTest[0];
// Remove this number of threads from the available runs
NumberOfThreadsPerTest.RemoveAt(0);
Console.WriteLine("Starting next benchmark with " + numberOfThreads + " thread(s)...");
// Get the start time
var startTime = DateTime.Now;
// Create an array to store the prime numbers
var primeNumbers = new List<int>();
// Calculate how many ints each thread will check
var countPerThread = MaxNumber / numberOfThreads;
// Create an array to store the created threads
var threads = new List<Thread>();
// Spawn the threads
for (var i = 0; i < numberOfThreads; i++)
{
// Create the range for this thread
var range = new PrimeRange
{
First = i * countPerThread + 1,
Last = i * countPerThread + countPerThread + 1
};
// Create the new thread
var t = new Thread(
// Specify the source files
new[]
{
// Include this javascript file (since bridge is loaded automatically)
Thread.GetCurrentJsFileUri()
}
);
// Start the thread
t.Start(
// Set the entry point to RunPrime
RunPrime,
// range is the parameter sent to the entry point
range,
// Set the completion callback when the thread returns a value (thread, original parameter, result)
(thread, param, result) =>
{
// Cast the result object to an int array
var resultPrimes = result as int[];
// Add the primes to the list of primes
primeNumbers.AddRange(resultPrimes);
}
);
// Add the created thread to the list of spawned threads
threads.Add(t);
}
// Wait for all threads to join
JoinAll(threads, () =>
{
// Get the end time
var endTime = DateTime.Now;
// Clean up all created threads
threads.ForEach(e => e.Dispose());
// Get the number of prime numbers found
var primeNumberCount = primeNumbers.Count;
if (PrintFirst1000Primes)
{
// Need to sort the primes array, since it is not in order
primeNumbers = primeNumbers.Slice(0, 1000);
primeNumbers.Sort();
// Print 100 rows of 10 primes
for (var i = 0; i < 100; i++)
{
var s = "";
for (var j = 0; j < 10; j++)
s += primeNumbers[i * 10 + j] + " ";
Console.WriteLine(s);
}
}
// Report the statistics from this run
Console.WriteLine("Max number: " + MaxNumber + ", Threads: " + numberOfThreads + ", Time taken: " +
(endTime - startTime).TotalMilliseconds + "ms, Number of primes: " +
primeNumberCount);
// Check if there are any more runs to do
if (NumberOfThreadsPerTest.Count > 0)
// Yes, run the next benchmark
BenchmarkPrimes();
else
{
// Run the baseline benchmark
RunBenchmarkOnMainThread();
// All done
Console.WriteLine("Complete.");
}
});
}
private static void RunBenchmarkOnMainThread()
{
Console.WriteLine("Starting baseline benchmark on main thread...");
// Get the start time
var startTime = DateTime.Now;
var primeNumbers = ((int[]) RunPrime(new PrimeRange
{
First = 1,
Last = MaxNumber + 1
})).ToList();
// Get the end time
var endTime = DateTime.Now;
// Get the number of prime numbers found
var primeNumberCount = primeNumbers.Count;
if (PrintFirst1000Primes)
{
// Need to sort the primes array, since it is not in order
primeNumbers = primeNumbers.Slice(0, 1000);
primeNumbers.Sort();
// Print 100 rows of 10 primes
for (var i = 0; i < 100; i++)
{
var s = "";
for (var j = 0; j < 10; j++)
s += primeNumbers[i * 10 + j] + " ";
Console.WriteLine(s);
}
}
// Report the statistics from this run
Console.WriteLine("Max number: " + MaxNumber + ", Threads: (Main Thread), Time taken: " +
(endTime - startTime).TotalMilliseconds + "ms, Number of primes: " + primeNumberCount);
}
[Ready]
public static void Start()
{
// Create a thread to demonstrate message passing
var t = new Thread(
// Specify the source files
new[]
{
// Include this javascript file (since bridge is loaded automatically)
Thread.GetCurrentJsFileUri()
}
);
// Set a message handler on the thread
t.OnMessage += o =>
{
// Print the message received from the thread
Script.Call("console.log", "Got message in main thread: ", o);
};
// Send a message to the worker
t.PostMessage("hello from main thread:)");
Window.SetTimeout(BenchmarkPrimes, 500);
}
// It is also possible to use threads without starting any thread start functions
// Just use Init and then check if the current thread is a web worker or not
[Init]
private static void MessagePassingThread()
{
if (!Thread.CurrentThread.IsWebWorker)
return;
// Set an on message handler for this web worker
Thread.CurrentThread.OnMessage += o =>
{
// log the received message
Script.Call("console.log", "Got message in worker: ", o);
// Send a message back in reply
Thread.CurrentThread.PostMessage("hello from the worker thread :)");
};
}
}
}