Parallel calculations: Difference between revisions

Content added Content deleted
mNo edit summary
(Added Wren)
Line 2,678: Line 2,678:
}
}
puts "$best = [renderFactors [dict get $results $best]]"</lang>
puts "$best = [renderFactors [dict get $results $best]]"</lang>

=={{header|Wren}}==
{{trans|C}}
{{libheader|OpenMP}}
{{libheader|Wren-math}}
<br>
Although all Wren code runs within the context of a fiber (of which there can be thousands) only one fiber can run at a time and so the language's virtual machine (VM) is effectively single threaded.

However, it's possible for a suitable host on a suitable machine to run multiple VMs in parallel as the following example, with a C host, shows when run on a machine with four cores. Four VMs are used each of which runs on its own thread.
<lang ecmascript>/* parallel_calculations.wren */

import "./math" for Int

class C {
static minPrimeFactor(n) { Int.primeFactors(n)[0] }

static allPrimeFactors(n) { Int.primeFactors(n) }
}</lang>
<br>
We now embed this Wren script in the following C program, compile and run it.
<lang c>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <omp.h>
#include "wren.h"

#define NUM_VMS 4

WrenVM* vms[NUM_VMS]; // array of VMs

void doParallelCalcs() {
int data[] = {12757923, 12878611, 12878893, 12757923, 15808973, 15780709, 197622519};
int i, count, largest, largest_factor = 0;
omp_set_num_threads(4);
// we can share the same call and class handles amongst VMs
WrenHandle* callHandle = wrenMakeCallHandle(vms[0], "minPrimeFactor(_)");
WrenHandle* callHandle2 = wrenMakeCallHandle(vms[0], "allPrimeFactors(_)");
wrenEnsureSlots(vms[0], 1);
wrenGetVariable(vms[0], "main", "C", 0);
WrenHandle* classHandle = wrenGetSlotHandle(vms[0], 0);

#pragma omp parallel for shared(largest_factor, largest)
for (i = 0; i < 7; ++i) {
int n = data[i];
int vi = omp_get_thread_num(); // assign a VM (via its array index) for this number
wrenEnsureSlots(vms[vi], 2);
wrenSetSlotHandle(vms[vi], 0, classHandle);
wrenSetSlotDouble(vms[vi], 1, (double)n);
wrenCall(vms[vi], callHandle);
int p = (int)wrenGetSlotDouble(vms[vi], 0);
if (p > largest_factor) {
largest_factor = p;
largest = n;
printf("Thread %d: found larger: %d of %d\n", vi, p, n);
} else {
printf("Thread %d: not larger: %d of %d\n", vi, p, n);
}
}

printf("\nLargest minimal prime factor: %d of %d\n", largest_factor, largest);
printf("All prime factors for this number: ");
wrenEnsureSlots(vms[0], 2);
wrenSetSlotHandle(vms[0], 0, classHandle);
wrenSetSlotDouble(vms[0], 1, (double)largest);
wrenCall(vms[0], callHandle2);
count = wrenGetListCount(vms[0], 0);
for (i = 0; i < count; ++i) {
wrenGetListElement(vms[0], 0, i, 1);
printf("%d ", (int)wrenGetSlotDouble(vms[0], 1));
}
printf("\n");
wrenReleaseHandle(vms[0], callHandle);
wrenReleaseHandle(vms[0], callHandle2);
wrenReleaseHandle(vms[0], classHandle);
}

static void writeFn(WrenVM* vm, const char* text) {
printf("%s", text);
}

void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
switch (errorType) {
case WREN_ERROR_COMPILE:
printf("[%s line %d] [Error] %s\n", module, line, msg);
break;
case WREN_ERROR_STACK_TRACE:
printf("[%s line %d] in %s\n", module, line, msg);
break;
case WREN_ERROR_RUNTIME:
printf("[Runtime Error] %s\n", msg);
break;
}
}

char *readFile(const char *fileName) {
FILE *f = fopen(fileName, "r");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
rewind(f);
char *script = malloc(fsize + 1);
fread(script, 1, fsize, f);
fclose(f);
script[fsize] = 0;
return script;
}

static void loadModuleComplete(WrenVM* vm, const char* module, WrenLoadModuleResult result) {
if( result.source) free((void*)result.source);
}

WrenLoadModuleResult loadModule(WrenVM* vm, const char* name) {
WrenLoadModuleResult result = {0};
if (strcmp(name, "random") != 0 && strcmp(name, "meta") != 0) {
result.onComplete = loadModuleComplete;
char fullName[strlen(name) + 6];
strcpy(fullName, name);
strcat(fullName, ".wren");
result.source = readFile(fullName);
}
return result;
}

int main(int argc, char **argv) {
WrenConfiguration config;
wrenInitConfiguration(&config);
config.writeFn = &writeFn;
config.errorFn = &errorFn;
config.loadModuleFn = &loadModule;
const char* module = "main";
const char* fileName = "parallel_calculations.wren";
char *script = readFile(fileName);

// config the VMs and interpret the script
int i;
for (i = 0; i < NUM_VMS; ++i) {
vms[i] = wrenNewVM(&config);
wrenInterpret(vms[i], module, script);
}
doParallelCalcs();
for (i = 0; i < NUM_VMS; ++i) wrenFreeVM(vms[i]);
free(script);
return 0;
}</lang>
{{out}}
Sample output as this will obviously vary depending on which threads return first and which of the three numbers (two the same) with a minimal prime factor of 47 is found first.
<pre>
Thread 0: found larger: 3 of 12757923
Thread 2: found larger: 29 of 15808973
Thread 0: found larger: 47 of 12878611
Thread 2: not larger: 7 of 15780709
Thread 1: not larger: 47 of 12878893
Thread 1: not larger: 3 of 12757923
Thread 3: not larger: 3 of 197622519

Largest minimal prime factor: 47 of 12878611
All prime factors for this number: 47 101 2713
</pre>

{{out}}
Sample output when the other (distinct) number is found first.
<pre>
Thread 0: found larger: 3 of 12757923
Thread 2: found larger: 29 of 15808973
Thread 1: found larger: 47 of 12878893
Thread 0: not larger: 47 of 12878611
Thread 2: not larger: 7 of 15780709
Thread 1: not larger: 3 of 12757923
Thread 3: not larger: 3 of 197622519

Largest minimal prime factor: 47 of 12878893
All prime factors for this number: 47 274019
</pre>


=={{header|zkl}}==
=={{header|zkl}}==