关于Python和Java的多进程多线程计算方法对比

Java fireling 17494℃ 0评论

搞大数据必须要正视的一个问题就是并行计算。就像执行一件任务一样,大伙一起同时干,才有效率,才会很快出成果。正所谓“众人拾柴火焰高”~

对于并行计算,有很多高大上的概念,我也不全懂。这里就单单罗列一下我对于多进程和多线程计算的理解和总结。

在计算机中,处理一个任务,可以在一个进程中,也可以在一个线程中,确切的说,执行的话都得靠一个个线程来。在我们做某件事的时候,往往需要同时干多个任务才能达到我们所要的效果,比如说看电影,就要让计算机实现让人“看”的任务,又要实现让人“听”的任务。计算机根据具体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的多进程多线程计算方法对比

喜欢 (54)

您必须 登录 才能发表评论!