疑似並行処理
もちろん可能であれば、疑似である必要はありません。^^;
Posted feedbacks - Nested
Flatten Hidden1 2 3 4 5 6 7 8 9 10 11 | import threading
import time
def p(x):
print x
time.sleep(0.001)
threads = [ threading.Thread(target=lambda ls: map(p, ls), args=(ls,))
for ls in (range(1,11), "ABCDEFGHIJ")]
for th in threads: th.start()
for th in threads: th.join()
|
処理系毎に異なりますが、差異を吸収するパッケージもあり、
今回は、その目的にportable-threadsを利用しています。
結果が上手く混ざらないので、それぞれ、短かいsleepをかませてあります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | (defpackage :doukaku-215 (:use :cl :portable-threads))
(in-package :doukaku-215)
(loop
:with ans := ()
:with tasks := (list
(spawn-thread "num"
(lambda ()
(dotimes (i 10)
(push i ans)
(sleep 0.001))))
(spawn-thread "char"
(lambda ()
(dotimes (i 10)
(push (code-char (+ 65 i)) ans)
(sleep 0.001)))))
;; wait
:while (every #'thread-alive-p tasks) :do (sleep 0.05)
:finally (return ans))
;=> (#\J 9 #\I 8 #\H 7 #\G 6 5 #\F #\E 4 #\D 3 #\C 2 #\B 1 #\A 0)
|
起動あたりの影響を受けずに混ざって出力されるよう、sleep 1しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #!/bin/bash
A(){
local i
for i in {1..10}; do
echo $i
sleep 1
done
}
B() {
local i
for i in {a..j}; do
echo $i
sleep 1
done
}
A & B
|
sleepをreturnに変えたら、疑似並行処理なコルーチンみたいなのになりました。
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 | #!/bin/bash
A() {
while ((i <= 10)); do
echo $((i++))
return
done
i=DONE
}
CHARS=({a..j})
B() {
while ((j < ${#CHARS[@]} )); do
echo ${CHARS[j++]}
return
done
j=DONE
}
doit() {
local i=1
local j=0
while [ $i != DONE -a $j != DONE ]; do
[ $i != DONE ] && A
[ $j != DONE ] && B
done
}
doit
|
さらに変形して継続渡しもどきに。
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 | #!/bin/bash
A() {
local i=$1
local cont=$2
if ((i <= 10)); then
echo $((i++))
if [ -n "$cont" ]; then
$cont "$FUNCNAME $i"
else
$FUNCNAME $i
fi
else
[ -n "$cont" ] && $cont
fi
}
CHARS=({a..j})
B() {
local i=$1
local cont=$2
if ((i < ${#CHARS[@]} )); then
echo ${CHARS[i++]}
if [ -n "$cont" ]; then
$cont "$FUNCNAME $i"
else
$FUNCNAME $i
fi
else
[ -n "$cont" ] && $cont
fi
}
A 1 'B 0'
|
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 | import java.util.concurrent.*;
public class test {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
final CyclicBarrier barrier = new CyclicBarrier(2);
try {
// その1
executor.submit(new Callable<Object>(){
public Object call() throws Exception {
for(int i = 1; i <= 10; i++) {
barrier.await();
System.out.println(i);
}
return null;
}
});
// その2
executor.submit(new Callable<Object>(){
public Object call() throws Exception {
for(char c = 'A'; c <= 'J'; c++) {
barrier.await();
System.out.println(c);
}
return null;
}
});
}
finally {
executor.shutdown();
}
}
}
|
適当な間隔で出力するように実装してみました
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 | #include <process.h>
#include <windows.h>
#include <time.h>
#include <stdio.h>
void PrintDigit(void* p_sleepTime)
{
int i;
for(i=1; i<=10; i++)
{
printf("%d\n", i);
Sleep(rand() % 300);
}
}
void PrintAlphabet(void* p_sleepTime)
{
int i;
for(i='A'; i<='Z'; i++)
{
printf("%c\n", i);
Sleep(rand() % 100);
}
}
int main()
{
HANDLE digit;
HANDLE alphabet;
srand(time(NULL));
digit = (HANDLE)_beginthread(PrintDigit, 0, NULL);
alphabet = (HANDLE)_beginthread(PrintAlphabet, 0, NULL);
WaitForSingleObject(digit, INFINITE);
WaitForSingleObject(alphabet, INFINITE);
return EXIT_SUCCESS;
}
|
スレッドをスタートするときに出力する文字列を渡しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | using System;
using System.Threading;
class Program
{
static void Main()
{
new Thread(state => Proc(state)).Start("abc");
new Thread(state => Proc(state)).Start("123");
}
static void Proc(object o)
{
foreach (var item in (string)o)
{
Console.WriteLine(item);
Thread.Sleep(1000);
}
}
}
|
スレッドセーフのコレクションへ出力しています。 a 1 b 2 c d 3 e f 4 g h 5 i j 6 7 8 9 10
System.ServiceModelへのアセンブリ参照を加えること
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 | using System;
using System.Collections.Generic;
using System.Threading;
class Program
{
static SynchronizedCollection<object> collection = new SynchronizedCollection<object>();
static void Main()
{
new Thread(state => Proc1(state)).Start();
new Thread(state => Proc2(state)).Start();
Thread.Sleep(3000);
foreach (var item in collection)
{
Console.WriteLine(item);
}
}
static void Proc1(object state)
{
char[] c = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' };
foreach (var item in c)
{
collection.Add(item);
Thread.Sleep(100);
}
}
static void Proc2(object state)
{
int[] n = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
foreach (var item in n)
{
collection.Add(item);
Thread.Sleep(200);
}
}
}
|
threadsモジュールを使って実行。 yieldでスレッドが明け渡される場合もあるけど、これくらいのコードだと全部実行されてしまうので sleep 1を入れてます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | use strict;
use threads;
threads->new(sub {
for (1..10) {
print $_. "\n";
sleep 1;
#threads->yield();
}
});
threads->new(sub {
for (my $a = 'A'; $a le 'J'; $a++) {
print $a. "\n";
sleep 1;
#threads->yield();
}
});
for my $t (threads->list()) {
$t->join();
}
|
OpenMPを使います。 gcc 4.2以上なら-fopenmp、iccなら-openmpというコンパイラオプションを付けます。 Visual C++ならオプションでOpenMPを有効にます。 結果: 1 A 2 B 3 C 4 D 5 E 6 F 7 G 8 H 9 I 10 J
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 | #include <iostream>
#include <string>
using namespace std;
void funcA() {
for (int i=1; i<=10; ++i) {
#pragma omp critical
cout<<i<<' ';
}
}
void funcB() {
string s="ABCDEFGHIJ";
for (size_t i=0; i<s.length(); ++i) {
#pragma omp critical
cout<<s.at(i)<<' ';
}
}
int main() {
#pragma omp parallel num_threads(2)
{
#pragma omp sections
{
#pragma omp section
funcA();
#pragma omp section
funcB();
}
}
}
|
Thread.passでスレッドを明示的にスイッチさせます。
これで手元では動いたけどスレッドというものの特性上、実行環境に依存しそう。
1 2 3 4 5 6 7 8 9 10 | [1..10, 'a'..'j'].map{|range|
Thread.start{
range.each{|e|
p e
Thread.pass
}
}
}.each{|thread|
thread.join
}
|
Thread.passを使って、一度に全部出力されてしまうのを避けてます。
1 2 3 4 5 6 7 8 | t1= Thread.new {
1.upto(10) { |i| print i; Thread.pass}
}
t2 = Thread.new {
'a'.upto('j') { |c| print c; Thread.pass}
}
t1.join
t2.join
|
あくまで擬似並行処理ということで。
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 | #include <stdio.h>
#include <stdlib.h>
#define TASK_END ((void*)-1)
/*
void put_num(){
int i;
for(i=0;i<10;i++){
putchar('0'+i);
fflush(stdout);
}
}
*/
void put_num(void **local){
/*ローカル変数定義*/
struct local_struct{
int i;
} *pl;
if(*local==NULL){
/*ローカル変数粋確保*/
*local =malloc(sizeof(struct local_struct));
pl=*local;
/*ローカル変数初期化*/
pl->i=0;
}else if(*local==TASK_END){
/*タスク終了済み*/
return;
}else
pl=*local;
/* タスク内容
キリのいいところでreturnする。
*/
for(;pl->i<10;){
putchar('0'+pl->i);
fflush(stdout);
pl->i++;
//タスクスイッチ
return;
}
//タスク終了処理
free(pl);
*local=TASK_END;
}
/*
void put_alpha(){
int i;
for(i=0;i<26;i++){
putchar('A'+i);
fflush(stdout);
}
}
*/
void put_alpha(void ** local){
/*ローカル変数定義*/
struct local_struct{
int i;
} *pl;
if(*local==NULL){
/*ローカル変数粋確保*/
*local =malloc(sizeof(struct local_struct));
pl=*local;
/*ローカル変数初期化*/
pl->i=0;
}else if(*local==TASK_END){
/*タスク終了済み*/
return;
}else
pl=*local;
/* タスク内容
キリのいいところでreturnする。
*/
for(;pl->i<26;){
putchar('A'+pl->i);
fflush(stdout);
pl->i++;
//タスクスイッチ
return;
}
//タスク終了処理
free(pl);
*local=TASK_END;
}
int main(){
void* local_n=NULL;
void* local_a=NULL;
while(local_n!=TASK_END||local_a!=TASK_END){
put_alpha(&local_a);
put_num(&local_n);
put_alpha(&local_a);
}
return 0;
}
|
シンプルにsetIntervalで疑似並列にしてみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | var outputarea;
function print(s) {
if(!outputarea) {
outputarea = document.createElement("p");
document.body.appendChild(outputarea);
}
outputarea.innerHTML += s;
}
function f(data, interval) {
var timer = setInterval(function() {
if(data && data.length > 0) {
print(data.shift());
} else {
clearInterval(timer);
}
}, interval);
}
var data_list = [
[1,2,3,4,5,6,7,8,9],
"abcdefghij".split("")
];
for(var i=0;i<data_list.length;i++) {
f(data_list[i], 100);
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | (use srfi-42)
(use gauche.threads)
(define (main args)
(let ((a (make-thread (lambda ()
(do-ec (: n 1 11)
(begin (display n) (thread-yield!))))))
(b (make-thread (lambda ()
(do-ec (: c #\a #\j)
(begin (display c) (thread-yield!)))))))
(thread-start! a)
(thread-start! b)
(thread-join! a)
(thread-join! b)
(newline))
0)
|
1 2 3 4 5 6 7 8 9 10 | (define loop
(lambda (c1 ls)
(and c1 (pair? ls)
(begin (display (car ls))
(loop (call/cc (lambda (c2) (c1 c2))) (cdr ls))))))
(let ((cc (call/cc (lambda (cc)
(loop cc '(1 2 3 4 5 6 7 8 9 10))))))
(loop cc '(A B C D E F G H I J))
(newline))
|
適当に出力が混ざるようにランダムに thread-yield! しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | (use srfi-27)
(use gauche.threads)
(define (my-for-each proc xs)
(cond ((pair? xs)
(when (< (random-real) 0.5) (thread-yield!))
(proc (car xs))
(my-for-each proc (cdr xs)))))
(begin
(for-each thread-join!
(map (lambda (xs)
(thread-start! (make-thread (cut my-for-each display xs))))
'((1 2 3 4 5 6 7 8 9 10)
(a b c d e f g h i j))))
(newline))
|
みんな普通に並行処理書いてるような気がするけど、 お題の「擬似」はどこに行ったんだろうと 思わなくもなく。 というわけで、Perl/Tkで擬似並行処理
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 | use strict;
use warnings;
use Tk;
my $lblvar='';
my $num = 1;
my $al = 'A';
# ウィンドウとラベル
# ラベルに文字が追加されていく
my $mw = Tk::MainWindow->new;
$mw->Label(-textvariable => \$lblvar)->pack(qw/-fill both/);
# Windowが表示されたらタイマ開始
$mw->bind(q/<Expose>/ => sub {
$mw->after(timergen() , \&append_number);
$mw->after(timergen() , \&append_alphabet);
});
$mw->MainLoop;
sub timergen
{ int rand 3000 };
sub append
{ $lblvar .= ($lblvar ? ',' : '') . shift; }
sub append_number
{
return if $num > 10;
append($num++);
$mw->after(timergen() , \&append_number);
}
sub append_alphabet
{
return if $al gt 'J';
append($al++);
$mw->after(timergen() , \&append_alphabet);
}
|
1 2 3 4 5 6 | import Data.Char
import Control.Concurrent
main = forkIO f >> g
where f = mapM_ (\x -> threadDelay 100000 >> putStr (show x)) [1..10]
g = mapM_ (\x -> threadDelay 100000 >> putChar x) ['A'..'J']
|
D2.020から言語コアと標準ライブラリが分離されました。 なぜか言語コアのほうに含まれているThreadGroupなるユーティリティクラスを使ってみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | private import core.thread, std.stdio;
void main() {
auto threads = new ThreadGroup;
threads.create({
foreach(x; "0123456789") {
write(x);
Thread.yield;
}
});
threads.create({
foreach(x; "abcdefghij") {
write(x);
Thread.yield;
}
});
threads.joinAll;
}
|
yieldが予約語だったことを忘れてて少し悩んだ。
1 2 3 4 5 6 | import scala.concurrent.ops._
object TwoThread extends Application {
spawn { ('a' to 'j').foreach{ x => print(x + " "); Thread.`yield` } }
spawn { ( 1 to 10 ).foreach{ x => print(x + " "); Thread.`yield` } }
}
|
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 | import System;
import System.Threading;
class Sample {
static function Main()
{
var t = new Sample();
t.doIt();
}
function doIt(){
var t1 = new Thread(numPrint);
var t2 = new Thread(charPrint);
t1.Start();
t2.Start();
}
function numPrint(){
for(var i=0;i<10;i++){
print(i+1);
}
}
function charPrint(){
var data = "abcdefghij"
for(var i=0;i<10;i++){
print(data.charAt(i));
}
}
}
Sample.Main();
|
1 | Thread.with{[0..9,'a'..'j'].each{x->start{x.each{print it;yield()}}}}
|
see: Nemerle
1 2 3 4 5 | using Nemerle.Concurrency;
foreach(n in ['0', 'a'])
async foreach(i in [0..9])
async Nemerle.IO.print((i + n) :> char)
|
Thread.yield だと切り替わらなかったのでThread.delayを使いました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | (* ocamlc -thread -o para unix.cma threads.cma para.ml *)
let para printer lst =
Thread.create
(fun lst ->
List.iter
(fun x ->
printer x;
flush stdout;
Thread.delay 0.1) lst) lst
let _ =
List.iter
(fun t -> Thread.join t)
[ para (fun c -> Printf.printf "%c " c)
['A'; 'B'; 'C'; 'D'; 'E'; 'F'; 'G'; 'H'; 'I'; 'J'];
para (fun i -> Printf.printf "%d " i)
[1; 2; 3; 4; 5; 6; 7; 8; 9; 10] ]
|
昔、シューティングゲームを作った時に スプライトの操作で似たようなことをした記憶がある。 並列実行というよりは、 Windowsのイベント処理みたいなものです このコードでは、ただのタイマ処理に近いけど、 ポーリングすることが目的だろうということで投下! ホントに並列実行させるようにしようと思うと Bのようにプログレス管理して再入可能にしないとだめなのかなー?(状態遷移) でも、そんなコーディングはしたくない(笑 // gcc -Wall -std=c99 doukaku215.c
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 | #include <stdio.h>
#include <sys/time.h>
typedef struct tagFRAMEINFO
{
time_t next;
int state;
void (*update)(struct tagFRAMEINFO *);
} FRAMEINFO;
void A(struct tagFRAMEINFO *info)
{
static const int num[] = {1,2,3,4,5,6,7,8,9,10};
static size_t index = 0;
printf("%d ", num[index ++]);
index %= 10;
info->next = time(NULL) + 1;
}
void B(struct tagFRAMEINFO *info)
{
switch( info->state ++ )
{
default: case 0: break;
case 1: printf("A "); break;
case 2: printf("B "); break;
case 3: printf("C "); break;
case 4: printf("D "); break;
case 5: printf("E "); break;
case 6: printf("F "); break;
case 7: printf("G "); break;
case 8: printf("H "); break;
case 9: printf("I "); break;
case 10: printf("J "); info->state = 0; break;
}
info->next = time(NULL) + 2;
}
int main( int argc, char *argv[] )
{
FRAMEINFO frame[] = { {0,0,A}, {0,0,B} };
time_t now;
setvbuf(stdout, NULL, _IONBF, 0);
while( 1 )
{
for( size_t n=0; n<(sizeof(frame)/sizeof(*frame)); n++)
{
now = time(NULL);
if( now >= frame[n].next )
{
frame[n].update( &frame[n] );
}
}
}
return 0;
}
|
タイマーを使って。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | I=0
A=0
数値タイマとはタイマー
これについて
値は10
時満ちた時は~
もし(I<=10)ならば
"{I} "を継続表示
I=I+1
違えば
停止
開始
英字タイマとはタイマー
これについて
値は10
時満ちた時は~
もし(A<=10)ならば
"{CHR(A+65)} "を継続表示
A=A+1
違えば
停止
開始
|
boost::thread版です。g++の場合は以下のようにコンパイルしてください。
g++ para.cxx -lboost_thread
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 | #include <string>
#include <iostream>
#include <boost/thread/thread.hpp>
class Proc
{
private:
std::string m_str;
public:
Proc(std::string s) : m_str(s) {}
void operator () (void)
{
for (int i = 0; i < m_str.size(); ++i)
{
std::cout << m_str[i] << std::flush;
}
}
};
int main(void)
{
Proc numbers("0123456789");
Proc alphabets("ABCDEFGHIJ");
boost::thread nt(numbers);
boost::thread at(alphabets);
nt.join();
at.join();
return 0;
}
|
よく考えてみると、これってマルチコアの場合、本当に並列処理するかもしれないので、お題の「擬似並列処理」からは外れてるかもしれません。
この例は1文字ずつだからいいのですが、 std::coutがスレッドセーフでない可能性を 考慮したコードにしておいたほうがいいと思います。
考慮しました。
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 | #include <string>
#include <cstdlib>
#include <iostream>
#include <boost/thread.hpp>
class Proc
{
private:
std::string m_str;
boost::mutex & m_mtx;
public:
Proc(std::string s, boost::mutex & m) : m_str(s), m_mtx(m) {}
void operator () (void)
{
for (int i = 0; i < m_str.size(); ++i)
{
usleep(1);
boost::mutex::scoped_lock lck(m_mtx);
std::cout << m_str[i] << std::flush;
}
}
};
int main(void)
{
boost::mutex mutex;
boost::thread numbers(Proc("0123456789", mutex));
boost::thread alphabets(Proc("ABCDEFGHIJ", mutex));
numbers.join();
alphabets.join();
return 0;
}
|
以下のようにして実行します。 erlc para.erl erl -noshell -s para para -s init stop
1 2 3 4 5 6 7 8 9 10 11 12 13 | -module(para).
-export([para/0]).
proc(Pid, []) -> Pid ! void;
proc(Pid, [Chr | Str]) ->
io:format("~s", [[Chr]]),
proc(Pid, Str).
para() ->
Pid = self(),
spawn(fun() -> proc(Pid, "0123456789") end),
spawn(fun() -> proc(Pid, "ABCDEFGHIJ") end),
receive _ -> receive _ -> void end end.
|
Makefileという名前で保存して、以下のように実行してください。(-jオプションは標準的ではないかもしれないので、もしかするとGNU Make専用かも)
make -j2
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 | all: numbers alphabets
numbers:
@echo 0
@echo 1
@echo 2
@echo 3
@echo 4
@echo 5
@echo 6
@echo 7
@echo 8
@echo 9
alphabets:
@echo A
@echo B
@echo C
@echo D
@echo E
@echo F
@echo G
@echo H
@echo I
@echo J
|
1 2 3 4 5 6 7 8 9 10 11 | import stackless
def put_iterator(it):
for i in it:
print i
stackless.schedule()
stackless.tasklet(put_iterator)('ABCDEFGHIJ')
stackless.tasklet(put_iterator)(range(1,11))
stackless.run()
|
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 | program thread;
{$APPTYPE CONSOLE}
uses
Classes, SyncObjs, SysUtils;
var
csConsole: TCriticalSection;
procedure SerializeWrite(const s: string);
begin
csConsole.Enter;
try
Write(s);
finally
csConsole.Leave;
end;
Sleep(1);
end;
type TWriteText = class(TThread)
private
FText: string;
protected
procedure Execute; override;
public
constructor Create(const Text: string);
end;
constructor TWriteText.Create(const Text: string);
begin
inherited Create(true);
FText := Text;
Resume;
end;
procedure TWriteText.Execute;
var
n: integer;
begin
for n := 0 to Length(FText) - 1 do
SerializeWrite(copy(FText, n + 1, 1));
end;
var
threadWrite0To9: TWriteText;
threadWriteAtoZ: TWriteText;
begin
csConsole := TCriticalSection.Create;
try
threadWrite0To9 := TWrite0to9.Create('0123456789');
threadWriteAtoZ := TWriteAtoZ.Create('ABCDEFGHIJ');
try
threadWrite0To9.WaitFor;
threadWriteAtoZ.WaitFor;
finally
FreeAndNil(threadWrite0To9);
FreeAndNil(threadWriteAtoZ);
end;
finally
FreeAndNil(csConsole);
end;
end.
|
1-10とA-Jのスマートな書き方がわからなかった。 sleep(0.01)を入れて、交互になるようにしてあります。 そうしないと、2つめのプロセス作る前に Print終わってしまう気がする。<交互にならない
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #!/usr/bin/env python
# coding:utf-8
from multiprocessing import Process
import time
def printStr(str):
for i in str:
print i
time.sleep(0.01) # 出力を緩慢に
if __name__ == '__main__':
strArr = [[i for i in range(1,10)],
['A','B','C','D','E','F','G','H','I','J']]
for str in strArr:
p = Process(target = printStr, args=(str,))
p.start()
|
ちょっと修正 無駄にめんどくさい事してた・・orz
1 2 3 4 5 | if __name__ == '__main__':
strArr = [range(1,10), 'ABCDEFGHIJ']
for str in strArr:
p = Process(target = printStr, args=(str,))
p.start()
|
range(1,10)だと1~9までしか出力されないと思う。
spawnを試す。 channelで子プロセスの終了を待つ。 出力 a0b1c2d3e4f5g6h7ij89
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 | implement d215;
include "sys.m";
include "draw.m";
d215: module{
init: fn(ctx: ref Draw->Context, argv: list of string);
};
sys: Sys;
init(ctx: ref Draw->Context, argv: list of string)
{
i: int;
ch := chan of int;
sys = load Sys Sys->PATH;
spawn print_num(ch);
for(i = 0; i < 10; i ++){
sys->print("%c", i + 'a');
}
<- ch;
}
print_num(ch: chan of int)
{
i: int;
for(i = 0; i < 10; i ++){
sys->print("%d", i);
}
ch <- = 0;
exit;
}
|
javascript 1.7 の yield で疑似並列。
see: JavaScript 1.7 の yield が凄すぎる件について - IT戦記
1 2 3 4 5 6 7 8 9 10 | function create_loop(data) {
for(var i=0,n=data.length;i<n;i++) {
print(data[i]);
yield true;
}
yield false;
}
var f1 = create_loop([1,2,3,4,5,6,7,8,9,10]);
var f2 = create_loop(['a','b','c','d','e','f','g','h','i','j']);
while(f1.next() & f2.next());
|
print関数の定義を忘れました。 以下のような関数があるものとしてください。
1 2 3 4 5 6 7 8 9 10 11 12 | var outputarea;
function print(s) {
if(!outputarea) {
outputarea = document.createElement("p");
document.body.appendChild(outputarea);
}
outputarea.innerHTML += s;
}
// あるいは
function print(s) {
console.log(s); // 要firebug
}
|
Erlang のプレーンな例は、他の方が解答されていましたので、あえて lists ライブラリを積極的に使ったパターンを投稿してみます。 ミソは、終了メッセージの選択受信かな?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | -module(doukaku215).
-author('cooldaemon@gmail.com').
-export([run/0]).
run() ->
Pid = self(),
lists:foreach(
fun (CPid) -> receive {CPid, finish} -> ok end end,
lists:map(
fun (Cs) -> spawn(fun () ->
lists:foreach(fun (C) -> io:fwrite("~s", [[C]]) end, Cs),
Pid ! {self(), finish}
end) end,
lists:map(fun (N) -> lists:seq(N, N+8) end, [$1, $A])
)
).
|
1 2 3 4 5 6 7 | #r "system.servicemodel.dll"
let sc = new System.Collections.Generic.SynchronizedCollection<obj>() in
let inline sc_add x = sc.Add(x); System.Threading.Thread.Sleep(64) in
[ async { Seq.iter sc_add {1..10} }; async { Seq.iter sc_add {'A'..'J'} } ]
|> (Async.Parallel >> Async.Run >> ignore);
sc |> Seq.to_list |> printfn "%A"
|
こんな風にcurry化って利用するものなのかな??
1 2 3 | run = { list, sleep -> list.each{ println it; Thread.sleep(sleep); } }
Thread.start run.curry('a'..'z', 100)
Thread.start run.curry(1..9, 200)
|
makecontext()とかでお手軽にコンテキストスイッチ。
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 | #include <ucontext.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define STACK_NUM 2
#define ITEM_NUM 10
#define ITEM_SIZE 3
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
static struct {
int pos;
struct {
ucontext_t ctx;
char stack[16384];
} proc[STACK_NUM];
} uctx;
static void next_uctx(void)
{
int old_uctx_pos = uctx.pos;
uctx.pos = (uctx.pos + 1) % STACK_NUM;
if (swapcontext(&uctx.proc[old_uctx_pos].ctx, &uctx.proc[uctx.pos].ctx) == -1)
handle_error("swapcontext");
}
static void func(char list[ITEM_NUM][ITEM_SIZE])
{
int i;
for(i = 0; i < ITEM_NUM; i++) {
printf("%s ", list[i]);
usleep(100);
next_uctx();
}
}
int main(int argc, char *argv[])
{
int i;
char lists[STACK_NUM][ITEM_NUM][ITEM_SIZE] = {
{ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" },
{ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J" },
};
ucontext_t uctx_main;
for(i = 0; i < STACK_NUM; i++) {
ucontext_t *ucp = &uctx.proc[i].ctx;
if (getcontext(ucp) == -1)
handle_error("getcontext");
ucp->uc_stack.ss_sp = uctx.proc[i].stack;
ucp->uc_stack.ss_size = sizeof(uctx.proc[0].stack);
ucp->uc_link = (i >= STACK_NUM - 1) ? &uctx_main: &uctx.proc[i + 1].ctx;
makecontext(ucp, (void (*)(void))func, 1, lists[i]);
}
if (swapcontext(&uctx_main, &uctx.proc[0].ctx) == -1)
handle_error("swapcontext");
exit(EXIT_SUCCESS);
}
|
Clojure です、トランザクション内で更新をかけるんですね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | (import '(java.util.concurrent Executors))
(defn- par
[& tasks]
(let [exe (.newCachedThreadPool Executors)]
(try
(.invokeAll exe tasks)
(finally (.shutdown exe)))))
(let [r (ref '())]
(par
(fn []
(dotimes n 10
(dosync (alter r #(cons (inc n) %)))
(.sleep Thread 1)))
(fn []
(dotimes n 10
(dosync (alter r #(cons (Character. (char (+ 64 (inc n)))) %)))
(.sleep Thread 1))))
@r)
;=>(\J 10 \I 9 \H 8 \G 7 \F 6 \E 5 \D 4 \C 3 \B 2 \A 1)
|
新しいリリースに追従しました。
static メソッドの呼び方、バインディングの記法を修正しました。
# conj を使うのが Clojure っぽいのかしらん。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | (defn- par
[& tasks]
(let [exe (java.util.concurrent.Executors/newCachedThreadPool)]
(try
(.invokeAll exe tasks)
(finally (.shutdown exe)))))
(let [r (ref [])]
(par
(fn []
(dotimes [n 10]
(dosync (alter r #(conj % (inc n))))
(Thread/sleep 1)))
(fn []
(dotimes [n 10]
(dosync (alter r #(conj % (Character. (char (+ 64 (inc n)))))))
(Thread/sleep 1))))
@r)
;⇒ [1 \A 2 \B 3 \C 4 \D 5 \E 6 \F 7 \G 8 \H 9 \I 10 \J]
|
pthreadに興味がわいたのでテスト。 gcc -lpthreadでコンパイル。 putcはスレッドセーフという前提です。 出力: a01bc23de45fg67hi89j
see: pthreadについて(概要・生成)
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 | #include <stdio.h>
#include <pthread.h>
void *thread_alpha(void *arg);
int main( int argc, char ** argv )
{
pthread_t pt;
int i;
int err;
err = pthread_create( &pt, NULL, &thread_alpha, NULL);
if(err){
return -1;
}
for(i = 0; i < 10; i ++){
putc('0' + i, stdout);
usleep(1);
}
/* スレッドの終了を待つ */
pthread_join( pt, NULL);
return 0;
}
void *thread_alpha(void *arg)
{
int i;
for(i = 0; i < 10; i ++){
putc_unlocked('a' + i, stdout);
usleep(1);
}
pthread_exit(0);
}
|
いちおう擬似並行処理といえるかな。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | def f(s):
for i in s:
print i,
yield i
def run(ths):
while ths:
for th in ths:
try:
th.next()
except StopIteration:
ths.remove(th)
run([f('ABCDEFGHIJ'), f(range(1,11))])
|
スレッドを使わない擬似並行処理です。 一行Pythonで119 bytes. 一行にするとループやgeneratorが使えないため、 lambdaのリストを巡回することで代用しています。
1 2 | import sys;F=lambda x:(lambda:sys.stdout.write(chr(x)));
[[p()for p in q]for q in [(F(i+48),F(i+65))for i in range(10)]]
|
スレッドつくって画面表示。最後のThread.delayは、これが無いとすぐに実行が終了してしまうので、待ちを入れる意味です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | open Format
let spawn_loop f x =
let rec forever f x =
let v = f x in forever f v
in
ignore (Thread.create (forever f) x)
let _ =
spawn_loop (fun () ->
List.iter (fprintf std_formatter "%d@?") [1; 2; 3; 4; 5; 6; 7; 8; 9; 10;]) ();
spawn_loop (fun () ->
List.iter (fprintf std_formatter "%c@?") ['A'; 'B'; 'C'; 'D'; 'E'; 'F'; 'G'; 'H'; 'I'; 'J']) ();
Thread.delay 10.
|
スレッド2つにしてみました。
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 | implement Channel;
include "sys.m";
sys: Sys;
include "draw.m";
Channel: module
{
init: fn(ctxt: ref Draw->Context, argv: list of string);
};
init(nil: ref Draw->Context, nil: list of string)
{
sys = load Sys Sys->PATH;
c1 := chan of int;
c2 := chan of int;
spawn task('A', 10, c1);
spawn task('0', 10, c2);
(<- c1, <- c2);
sys->print("\n");
}
task(bp, n: int, c: chan of int)
{
for(i := 0; i < n; i++)
sys->print("%c", bp+i);
c <- = 0;
}
|
初チャレンジ。 Lua のコルーチンで for ループを素朴に使っています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | function mkfunc (printfunc)
return function ()
for v = 1, 10 do
printfunc (v)
coroutine.yield ()
end
end
end
function printalpha (n)
print (string.char (n + string.byte ("A") - 1))
end
function costat (c)
return coroutine.status (c) == "suspended"
end
local c, d = coroutine.create (mkfunc (print)),
coroutine.create (mkfunc (printalpha))
while costat (c) or costat (d) do
coroutine.resume (c)
coroutine.resume (d)
end
|
Executorを使いたかったので。
see: 第6回 並行プログラミング用ライブラリ(1)――Excecutorの仕組み
1 2 3 | exec = java.util.concurrent.Executors.newCachedThreadPool()
[1..9,'a'..'z'].each{r->exec.submit({r.each{println it;Thread.yield()}})}
exec.shutdown()
|
普通にfork(2)で子プロセスを作る例が無かったので,書いてみました.
子プロセスの実行開始のタイミングをそろえるために,signalを使っています.また,ほどよく出力が混ざるように適宜usleepしています.
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 | #include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
#define ITEMS_MAX 10
#define CHILD_MAX 2
#ifndef false
# define false 0
#endif
#ifndef true
# define true !false
#endif
static int is_activated = false;
static const char *table[][ITEMS_MAX + 1] = {
{ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" },
{ "A", "B", "C", "D", "E", "F", "G", "H", "I", "J" },
};
int child_proc(pid_t, const char **);
void child_activate(int);
int
main(int argc, void **argv)
{
int i;
pid_t children[CHILD_MAX];
memset(children, -1, sizeof(children));
/* create child processes */
for (i = 0; i < CHILD_MAX; i++) {
if ((children[i] = fork()) == -1)
exit(EXIT_FAILURE);
else if (children[i] == 0)
_exit(child_proc(getpid(), table[i]));
}
/* activate all of children by sending signal */
usleep(100000);
for (i = 0; i < CHILD_MAX; i++)
kill(children[i], SIGUSR1);
/* wait until all child processes finish */
for (i = 0; i < CHILD_MAX; i++) {
int status;
if (wait(&status) == -1)
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
void
child_activate(int signum)
{
is_activated = true;
}
int
child_proc(pid_t my_pid, const char **table)
{
int c;
struct sigaction act;
/* waiting signal from the parent */
memset(&act, 0, sizeof(act));
act.sa_handler = child_activate;
if (sigaction(SIGUSR1, &act, NULL) != 0)
return EXIT_FAILURE;
sleep(60);
if (!is_activated)
return EXIT_FAILURE; /* timed out */
/* process something */
for (c = 0; c < ITEMS_MAX; c++) {
printf("%s ", table[c]);
fflush(stdout);
usleep(10000);
}
printf("\n");
return EXIT_SUCCESS;
}
|
疑似ではなくちゃんと並列になってる……はず.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | component doukaku215
import List.{...}
export Executable
run(args: String...): () = do
do
for i <- 0#10 do
t = spawn print i ", "
t.wait()
end
also do
for c <- <|"A", "B", "C", "D", "E", "F", "G", "H", "I", "J"|> do
t = spawn print c ", "
t.wait()
end
end
print "\n"
end
end
|
1 2 3 4 5 6 7 8 9 10 11 12 | randomize
sdim buf
cntAlph = 0
cntDig = 0
repeat 26
buf += cntDig
buf += strf("%c", 'A'+ cntAlph)
cntDig ++
cntAlph ++
loop
mes buf
|
Clojure1.1.0
1 2 3 4 5 6 7 8 9 | (def out (ref []))
(defn put [sq]
(doall (map #(dosync (Thread/sleep 10) (alter out conj %)) sq)))
(pcalls #(put [1 2 3 4 5 6 7 8 9 10])
#(put [:a :b :c :d :e :f :g :h :i :j]))
(println @out)
|






sumim
#7912()
[
Smalltalk
]
Rating5/7=0.71
数値(たとえば1から10)と、アルファベット(たとえばAからJまで)を順に出力する別々のループ処理を並行に実行させ、共通の出力先に出力する極力シンプルなコードを書いてください。
念のため、実行後、出力先に数値とアルファベットが混ざって出力されている(たとえば、数値がすべて出力されてからアルファベットが続く…というふうになっていない)ことを確認してください。混ざってさえいれば、それぞれ1文字ずつ交互である必要はありませんし、もちろん交互でも構いません。
出力先や出力方法は自由です。標準出力、テキストファイル、コンテナオブジェクト(配列、リスト、コレクション)など使いやすいもので構いません。
例として Squeak Smalltalk でのコードと結果を示します。シンプルなコードなので Smalltalk に馴染みがない人も、おおよその内容は掴めると思います。
Rating5/7=0.71-0+
1 reply [ reply ]