搞大数据必须要正视的一个问题就是并行计算。就像执行一件任务一样,大伙一起同时干,才有效率,才会很快出成果。正所谓“众人拾柴火焰高”~
对于并行计算,有很多高大上的概念,我也不全懂。这里就单单罗列一下我对于多进程和多线程计算的理解和总结。
在计算机中,处理一个任务,可以在一个进程中,也可以在一个线程中,确切的说,执行的话都得靠一个个线程来。在我们做某件事的时候,往往需要同时干多个任务才能达到我们所要的效果,比如说看电影,就要让计算机实现让人“看”的任务,又要实现让人“听”的任务。计算机根据具体CPU的情况,开多个进程,而每个进程,又可以有多个线程。
先说“多进程”:
在Python中,实现多进程是比较容易的。我们可以使用multiprocessing进行进程的创建,比如说
import multiprocessing as mp p = mp.Process(target=run_proc, args=('fireling',), name='Run_procProcess') p.start() p.join()
这样就创建了一个进程,用p表示,其中run_proc表示你用子进程运行的函数。
如果觉得这样不过瘾,还可以采用进程池创建多个进程,涉及到了两种用法:pool-apply用法和pool-map用法,本质上跟创建单个进程是一样的。
还是要用到multiprocessing包,先创建一个进程池
p = mp.Pool() p.map(run_proc, [i for i in range(m)]) p.close() p.join()
在Java中,程序都是在JVM上运行的,一个JVM占一个进程,所以多进程的概念,应该不存在。
再说“多线程”:
和多进程的思路类似,我们也可以实现对线程的创建,在Python中,使用threading包实现。比如说
import threading t = threading.Thread(target=run_thread, args=('fireling', ), name='Run_threadThread') t.start() t.join()
这样就创建了一个线程,用t表示,其中run_thread表示你用子线程运行的函数。
但是由于多线程处理任务,往往有些变量由所有线程共享,这种变量叫全局变量,在所有线程中,这种变量只保存一份。所以多线程处理任务,特别是对于全局变量修改的时候,我们往往要加线程锁,保证在对某个全局变量修改的时候,只有一个线程接触到它。
首先要先声明线程锁,
lock = threading.Lock()
在这些线程调用的函数定义中,我们可以加两句话:
lock.acquire() # 获取线程锁 xxxxxxxxxxx 此处省略若干代码 lock.release() # 释放线程锁
全局锁针对的是所有线程的全局变量,那么我们如果要处理单个线程的局部变量呢?可以用到ThreadLocal方法。
在Java中并行计算要涉及多线程。同样的,在一个JVM进程空间中,存在多个栈来记录多个线程的调用,但是这些线程共享堆中的对象,也就是说,对这些对象的修改,也需要加线程锁机制。
Java中实现多线程主要有两种方法:继承Thread类来创建线程,并提供run()方法,或者实施Runnable接口来创建线程,并提供run()方法。
如果二者同时存在,它会首先找子类的run方法,如果子类没有重写run,则再找Runnable接口的run方法。下面的例子,说明了这个结论,最后输出的是子类重写run方法的输出。
public class Test { public static void main(String[] args) { Thread thread = new Thread(new Runnable() { @Override public void run() { while(true) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Runnable1:" + Thread.currentThread().getName()); // System.out.println("Runnable2:" + this.getName()); } } }) { @Override public void run() { while(true) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread1:" + Thread.currentThread().getName()); System.out.println("Thread2:" + this.getName()); } } }; thread.start(); } }
与Python对应的是,Java线程锁是通过同步机制来实现的,也就是synchronized方法。同一对象的synchronized方法只能同时被一个线程调用。其他线程必须等待该线程调用结束才能运行,排除了多线程同时修改全局变量的可能。
值得一提的是,Python中对应的全局变量用关键字global表示,而java和C/C++中用static来表示。
关于”协程“:
Python能实现多个线程,但是实际上无法充分利用系统资源,原因在于Python存在全局锁机制,简单来说,就是同一时刻在一个进程中只能有一个线程对数据进行操作。所以实现并行效果,采用多进程方法,比较好。
协程在一定程度上解决了这个问题。协程机制,就是在运行某个任务的过程中,我们可以随时中断,去执行另一任务,也可能随时再回来执行老任务。这在网络传输,IO过程中很有用,特别是对于两个不相关的任务来说,使用协程能达到异步执行的效果。
Java,不知道有没有这种机制。虽然xxxx,但是Java也不错的啦~~~在TIOBE编程语言排行榜一直稳坐头把交椅,这里面,无非Android开发给了Java这个优势。
转载请注明:宁哥的小站 » 关于Python和Java的多进程多线程计算方法对比