On a Ubuntu 16.04 virtual machine with 4 CPUs, I did a simple comparison on the performance of pyspark vs pure python. I run spark as local installation on the virtual machine with 4 cpus.
#!/home/python3/venv/bin/python3
import pyspark
from pyspark.sql import SparkSession
from operator import add
from datetime import datetime
spark = SparkSession.builder.appName('ai_project').getOrCreate()
len = 1000000000
for i in range(1):
start = datetime.now()
print("start:", start)
t=spark.sparkContext.parallelize(range(len))
a = t.fold(0, add)
print(a)
end= datetime.now()
print("end for spark sum:", end, end-start)
s = 0
start = datetime.now()
print("start for loop sum:", start)
for i in range(len):
s = s + i
print("sum=", s)
end= datetime.now()
print("end for loop sum:", end, end-start)
Here is the output:
(venv) cju@ubuntu-16:~/cloudmap3-ai-datasets/examples$ ./t1.py
20/05/15 10:22:34 WARN Utils: Your hostname, ubuntu-16 resolves to a loopback address: 127.0.1.1; using 192.168.2.113 instead (on interface enp0s3)
20/05/15 10:22:34 WARN Utils: Set SPARK_LOCAL_IP if you need to bind to another address
20/05/15 10:22:35 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Using Spark's default log4j profile: org/apache/spark/log4j-defaults.properties
Setting default log level to "WARN".
To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).
start: 2020-05-15 10:22:36.771454
49999999995000000000
end for spark sum: 2020-05-15 10:36:34.811598 0:13:58.040144
start for loop sum: 2020-05-15 10:36:34.811630
sum= 49999999995000000000
end for loop sum: 2020-05-15 10:47:53.770664 0:11:18.959034
The questions are:
1. pyspark code took 13:58 minutes and the pure python code took 11:18
minutes. when pyspark code is running, 4 CPUs is at 100%
utilization. when pure python code is running, only 1 CPU is at 100%
utilization. I would expect the pyspark code take much less time.
2. Another question is about the add operator. Is the add operation
done in a python process and the result is communicated back to JVM?
Or the add operation is done in the JVM of the worker process?
3. add is not a udf. It should be running in JVM rather than in a
python process. Could someone explain more?
Changing fold to reduce gives the same result. I also tried using dataframe to do the sum. But it is even worse. When the dataframe sum is running, only one CPU is at 100%. Also dataframe is using much more memory and much more slow. Here is the comparison:
--------------------------------------------------
|len |pyspark rdd|pyspark dataframe|pure python|
--------------------------------------------------
|10^7 |1.39sec |16.36sec |0.67sec |
--------------------------------------------------
|10^8 |7.02sec | out of memory |6.94sec |
--------------------------------------------------
|10^9 |13:58min | out of memory |11:18min |
--------------------------------------------------