一个生成10的N次方个整数的一段小程序,彰显出的大智慧

一个生成10的N次方个整数的一段小程序,彰显出的大智慧

魏仁言 2010.8.28

  最近在学习Hadoop,上次用Map/Reduce模型写个了对大量整数数字求和的程序,为了测试就要生成大量测试数据,我用Ruby写了个随机生成整数,并将整数按指定的格式写入文本文件,然后将生成的数据输入Map/Reduce程序(NumerSum),进行求和。针对这样的小功能我相信学过编程的都能写出来,因为这个问题很简单,实际要做的就是给定一个数值N,它来定义生成的数据量,当N=3时,就是生成1000个随机数字然后将数据写入文件,生成过程用For循环,循环个1000次就可以了。我想要的结果是生成的数据文>=10M,最低要求至少N>=5,反正是多多益善。现在问题与相应的解决方法也有了,下面我就逐步介绍下我的整个实现过程。

 

 问题:生成一个包含有10的N次方个整数的文本文件,N可以无限大,程序的运行时间要在可以忍受的程度,就是说程序的性能要求比较高。

 解决方法:

 1.定义一个数组m,通过Random生成随机数n,将数值n存入数组m内,并且随机数要包含有负数,限定随机数n值在-99=

 2.从数组m内,读取生成的结果,写入文件num.txt

 

  我分别用两种方式去实现我的代码,第1种方式是用简单的循环方法实现的,第2种方式是用多线程将要生成的整数任务,分解成多个小任务,分配给T个线程去执行,每个线程执行完成后,将其运行结果进行输出到指定的文件内。

 

  第一种实现代码>>

#!/usr/bin/ruby puts "Hello, World.../n"; #写文件方法 def write(filename,context) out=File.open(filename,"a") out.write(context) out.close end start=Time.now puts "Start...#{start}" n=10**5 nmu="" a=[] #生成数组数值 for i in 0..n-1 if i%3==0 && i%2==0 a[i]=-rand(100) elsif i%4==0 && i%5==0 a[i]=-rand(100) #a[i-1]=-a[i-1] else a[i]=rand(100) end end #puts a.join(" ") #读取数组内的值,写入文件 i=0 while i=n-1 u=n-1 end #每一行10个整数 str=a[i..u].join(" ") + "/n" write("num.txt",str) #puts str i+=10 end ed= Time.now cs=ed-start puts "End...#{ed}" puts "Consnum..#{cs}s /n/n" #puts a.join(" ") #打印所有整数的和 s=0 a.each do |i| s+=i end puts s

 

第二种实现代码>>

#!/usr/bin/ruby require 'thread' puts "Hello, World.../n"; #写文件方法 def write(filename,context) out=File.open(filename,"a") out.write(context) out.close end #将生成的数据写入文件 def writeArr(arr) i=0 n=arr.length str="" while i=n-1 u=n-1 end #每一行10个数字 str=str + arr[i..u].join(" ") + "/n" #缓存处理写文件 if ((u+1)%(200000) == 0) || (u==n-1) write("num.txt",str) str="" end i+=10 end end threads = [] n=6 #生成整数的数量 N=10**n #线程数量 T=4*10**(2) #n:5,T:20;n:6,T:600;n:7,T,7000 mutex = Mutex.new starts=Time.now puts "Start Threads...#{starts}" T.times { |i| #定义线程 threads << Thread.new(i) { puts i arr=[] count=0 l=0 u=N/T #每个线程要生成的整数数量 start=Time.now puts "Start Thread-#{i}...#{start}" loop do #mutex.synchronize do #puts count if count>u-1 #puts arr.join(" ") ed= Time.now cs=ed-start puts "End Thread-#{i}...#{ed}" puts "Consnum..#{cs}s /n/n" puts count-1 #mutex.synchronize do writeArr(arr) #end tt = Thread.current tt.exit end #随机生成整数 index=count if index%3==0 && index%2==0 arr[index] = -rand(10000) elsif index%4==0 && index%5==0 arr[index] = -rand(10000) #arr[index-1]=-arr[index-1] else arr[index] = rand(10000) end count+=1 #end end } #运行线程 threads[i].run } puts "Init Complete" threads.each {|t| t.join } eds= Time.now css=eds-starts puts "End Threads...#{eds}" puts "Consnum..#{css}s /n/n" puts "Done Complete" 

 

程序运行结果:

生成100000个整数,N=5时,

实现1. 9.39s

实现2.1.453s

 

我们都知道通过多线程并行计算的方式,可以提高程序运行的性能。当我用“实现1”去计算10^10个整数时,运行时间太长了,所以我就想能否用线程的方式,来缩短运行时间,这时我就快速地想出了“实现2”的大体思路,并将代码写出来,写出后运行结果与我预想的太差了,运行时间比“实现1”要多好几倍,经过多次调试,我终于明白了问题所在,并最终明白其内部所体现的智慧。

 

运行性能关键点:

1.线程的数量

2.每个线程要生成整数的数量

3.并行频繁地写入文件,文件写入等待

 

针对问题所在,我的处理措施如下:我通过对要生成整数的数量,指定相应线程数量及每个线程要处理的数量,

1.任务分解:

   每个线程要生成整数的数量=要生成整数的数量/运行线程的数量

一定数量的整数生成,要有相应的线程去运行,不能多也不能少,少的话每个线程的任务太重,太少则线程对象自身的创建与销毁就占了太多时间,有点反客为主的意思。

  例如:当N=5时,T=20, 运行时间1.453s:

           当N=5时,T=50, 运行时间1.563s

           当N=6时,T=50, 运行时间39.141s

           当N=6时,T=200, 运行时间21.36s

           当N=6时,T=500, 运行时间15.922s

           当N=6时,T=600, 运行时间16.593s

2.运用缓存:

当线程数量太大的时候,大家都去写文件,这时为了等待写入文件的时间,就占用整个生成时间70%还多;我通过缓存的方式,在写入文件时,每次读取20000个整数写一次,直到读完为至;不是每读取一个整数就写进去。

例如:当N=5时,T=50, 运行时间15.656s:  //没有用缓存机制

         当N=5时,T=50, 运行时间1.563s: //用缓存机制

 

在学习的过程中,我理解到在用Hadoop处理数据时,用Map方法,对输入数据进行分解很重要,以及要用多少个Map Tasker,这个数量一定要根据输入数据量的大小来指定。在数据输出时,可以对其进行多次合并,减少数据输出量,从而提高整个程序运行性能。

 

注:如需转载,请注明出处,谢谢。

http://blog.csdn.net/savechina

你可能感兴趣的:(Hadoop,Ruby)