Python-多线程与并行计算
饿死我了。。。。今天看图像处理cuda的时候看到了并行计算,又恰巧参加第二届CCF举办CCSP比赛的时候,第五题是可以并行计算的。。。在赛后分享上,听清华大佬讲得栩栩如生,我听得一愣一愣的。真的是嘴上笑嘻嘻,心理妈卖批。不过还是比较羡慕他们怎么懂这么多,竞赛也这么强。扯远了,由于C++太繁琐,今天只是浅尝辄止用Python搜集了下资料,顺便跑了下。
科普开始。。。。。Loading
并行计算和多线程的区别
1,很明显并行比多线程具有更高的CPU利用率,因此效率相对更高;
2,并行是利用CPU的多个核进行计算,而多线程是利用CPU一个核在不同时间段内进行计算。
3,并行计算式多个线程运行在多个cpu上, 多线程是多个线程运行在一个cpu上, 并行计算基本是依赖多线程的。
4,多线程是一个线程只能运行在一个CPU,多个线程可以运行在多个CPU;并行计算是一个线程可以运行在多个CPU。
上述讲得很清晰,说白了,并行计算有多个线程和多个进程来实现。其中并行计算可以在多核上运行,多CPU(联机,分布式)上运行。多线程则只能在单个CPU跑,通过信号量,互斥锁来实现并发。做软件的时候,UI设计通常不同按钮要分发给不同的线程。因为你点击这个按钮的时候,窗口资源你在用,如果没有执行完,你立马点击下一个按钮,这就会产生死锁,程序奔溃。所以得分发给不同的线程,让他们同步运行。
进程与线程优缺点
进程优点:编程、调试简单,可靠性较高。
进程缺点:创建、销毁、切换速度慢,内存、资源占用大。
线程优点:创建、销毁、切换速度快,内存、资源占用小。
线程缺点:编程、调试复杂,可靠性较差。
场景使用
a.多核CPU——计算密集型任务。此时要尽量使用多进程,可以提高任务执行效率,例如加密解密,数据压缩解压缩(视频、音频、普通数据),否则只能使一个核心满载,而其他核心闲置。
d.多核CPU——IO密集型任务,这就更不用说了,跟单核时候原因一样
同样在这个单核时代,多线程的这个消除阻塞的作用还可以叫做“并发”,这和并行是有着本质的不同的。并发是“伪并行”,看似并行,而实际上还是一个CPU在执行一切事物,只是切换的太快,我们没法察觉罢了。例如基于UI的程序(俗话说就是图形界面),如果你点一个按钮触发的事件需要执行10秒钟,那么这个程序就会假死,因为程序在忙着执行,没空搭理用户的其他操作;而如果你把这个按钮触发的函数赋给一个线程,然后启动线程去执行,那么程序就不会假死,继续相应用户的其他操作。但是,随之而来的就是线程的互斥和同步、死锁等问题
特别:线程必然不是越多越好,线程切换也是要开销的,当你增加一个线程的时候,增加的额外开销要小于该线程能够消除的阻塞时间,这才叫物有所值。
总结
并发:
一、多进程并发
对于计算密集型程序,多进程并发优于多线程并发。密集型程序是运行时间大部分消耗在CPU的运算了。
而硬盘和内存的读写消耗时间很多;相对地,IO密集型程序是指程序运行大部分消耗在硬盘了,CPU的运算时间很短。
1.1采用队列实现-使用multiprocessing.JoinableQueue
1.2进程池实现-使用concurrent.futures.ProcessPoolExecutor
二、多线程并发
对于IO密集型程序多线程并发可能要优于多进程并发。
2.1 队列实现-使用使用queue.Queue
2.2 线程池实现-concurrent.futures.ThreadPoolExecutor
多线程:
http://www.runoob.com/python/python-multithreading.html
实例
多线程求和:
#coding: UTF-8
"""
经过非正规的测试,多线程并行计算并未像想象中那样会比串行计算快。
相反,在我的PC上运行后,多线程并行计算反而慢了。
不知是计算量不够大,还是怎么。(本身内存有限,无法无限加大,在有限测试范围内,结果如上)
过程是:随着计算线程数的增加,计算时间会下降,但到了一定数量(不同机器有所不同)后,计算时间反而增加。
因为很大一部分增加的时间是耗费在线程的创建上的。
"""
import threading
import random
import time
class calthread(threading.Thread):
#初始化函数
def __init__(self,threadname,cond,startN,endN):
threading.Thread.__init__(self,name = threadname)
self.cond = cond
self.startN = startN
self.endN = endN
#print "MyName: " + threadname +",start--" +str(startN) +",end--"+str(endN)
#业务函数
def run(self):
global sumN,alist,countFinish
temp = 0
for i in range(self.startN,self.endN + 1):
temp = temp + alist[i]
#累加计算和,并累加完成计数器
self.cond.acquire()
countFinish += 1
sumN += temp
#print "MyName: " + self.getName() +",mySum--" +str(temp) +",countFinish--"+str(countFinish)+",currentTotalSum---"+str(sumN)+"\n"
global threadN
if(countFinish == threadN):
print "End time of threadCal -- " + str(time.time())
print "The total sum : " + str(sumN) + "\n"
self.cond.release()
#获取线程锁
cond = threading.Condition()
#目标计算数组的长度
alen = 10000000
#执行计算工作的线程长度
threadN = 10000
#随机初始化数组元素
alist = []
#alist = [random.uniform(1,1000) for x in range(0,alen)]
for i in range(1,alen+1):
alist.append(i)
#执行线程对象列表
threadL = []
t = alen/threadN
print "初始化线程"
for x in range(0,threadN):
startN = x*t
endN = 0
if((x+1)*t >= alen):
endN = alen - 1
else:
if(x == threadN - 1):
endN = alen - 1
else:
endN = (x+1)*t - 1
#向列表中存入新线程对象
threadTT = calthread("Thread--"+str(x),cond,startN,endN)
threadL.append(threadTT)
#总计完成线程计数器
countFinish = 0
sumN = 0
print "Start time of threadCal--"+ str(time.time())
for a in threadL:
a.start()
time.sleep(10)
normalSum = 0
print "Start time of normalCal--"+ str(time.time())
for n in range(0,alen):
normalSum += alist[n]
print "End time of normalCal--"+ str(time.time())
print "Normal : " + str(normalSum) + "\n"
多线程求和:
import threading
from math import ceil
result = 0
def sub_sum(start, end, step):
global result
sum = float(0)
temp = start
while temp < end + step / 1000000:
sum += temp
temp += step
#print("sum from %f to %f by the step %f is %f"\
# % (start, end, step, sum))
result += sum
def thread_sum(start, end, step = 1, num_thread = 1):
global result
num_threads = int(num_thread)
if (num_threads <= 0):
num_threads = 1
end = start + int((end - start)/step) * step
numbers = end - start
if (numbers < 0 and step > 0) or (numbers > 0 and step < 0):
print("error in sum: from %f to %f by the step %f is invalid."\
% (start, end, step))
return 0
elif numbers == 0:
return start
if numbers < 0:
(start, end, step) = (end, start, -step)
numbers *= -1
d = ceil(numbers / num_thread / step) * step
if d < step:
d = step
begin = 0
threads = []
while start + begin * d < end:
threads.append(threading.Thread(target=sub_sum,\
args=(start + d * begin,\
start + d * (begin + 1) - step \
if start + (begin + 1) * d < end else end,\
step)))
begin += 1
print("Actual threads count: %d" % len(threads))
for i in range(len(threads)):
threads[i].start()
for i in range(len(threads)):
threads[i].join()
return result
if __name__ == "__main__":
start = raw_input("Please input the start: ")
end = raw_input("Please input the end: ")
step = raw_input("Please input the step(default 1): ")
start = float(start)
end = float(end)
step = 1 if step == "" else float(step)
num_thread = raw_input("Please input the num of threads: ")
num_thread = int(num_thread)
if num_thread < 0:
print("The num_thread must be positive but not %d" % num_thread)
exit(0)
print("Ths sum is: %f" % thread_sum(start, end, step, num_thread))
s = 0
if start < end and step > 0:
while start <= end:
s += start
start += step
elif start > end and step < 0:
while start >= end:
s += start
start += step
print("normal function: %s" % s)
多线程打印1-100
#encoding=utf-8
import threading
import time
threadLock = threading.Lock()
num = 0
class timer(threading.Thread):
def __init__(self, count, interval):
threading.Thread.__init__(self)
self.interval = interval
self.count = count
def run(self):
global num
while True:
# get lock
threadLock.acquire()
if num >= self.count:
threadLock.release()
break
num += 1
print 'Thread name:%s, %d' % (self.getName(), num)
threadLock.release()
time.sleep(self.interval)
if __name__ == '__main__':
thread1 = timer(1000, 1)
thread2 = timer(1000, 1)
thread1.start()
thread2.start()
thread2.join()
thread2.join()
多进程打印1-100
import multiprocessing
def create_process(tasks):
cpu_count = multiprocessing.cpu_count()
for _ in range(cpu_count):
process = multiprocessing.Process(target=_worker, args=(tasks, ))
process.daemon = True
process.start()
print "process_id-->{}".format(process.pid)
def _worker(tasks):
while True:
try:
task = tasks.get()
print "process_id--> {0}, task--> {1}".format(multiprocessing.current_process(), task)
finally:
tasks.task_done()
def add_task(tasks, task_count):
for item in range(task_count):
tasks.put(item)
def main():
max_num = 10000
tasks = multiprocessing.JoinableQueue()
create_process(tasks)
add_task(tasks, max_num)
tasks.join()
if __name__ == '__main__':
main()
并行实例
#-*- coding: UTF-8 -*-
import math, sys, time
import pp
def IsPrime(n):
"""返回n是否是素数"""
if not isinstance(n, int):
raise TypeError("argument passed to is_prime is not of 'int' type")
if n < 2:
return False
if n == 2:
return True
max = int(math.ceil(math.sqrt(n)))
i = 2
while i <= max:
if n % i == 0:
return False
i += 1
return True
def SumPrimes(n):
for i in xrange(15):
sum([x for x in xrange(2,n) if IsPrime(x)])
"""计算从2-n之间的所有素数之和"""
return sum([x for x in xrange(2,n) if IsPrime(x)])
inputs = (100000, 100100, 100200, 100300, 100400, 100500, 100600, 100700)
# start_time = time.time()
# for input in inputs:
# print SumPrimes(input)
# print '单线程执行,总耗时', time.time() - start_time, 's'
# # tuple of all parallel python servers to connect with
ppservers = ()
#ppservers = ("10.0.0.1",)
if len(sys.argv) > 1:
ncpus = int(sys.argv[1])
# Creates jobserver with ncpus workers
job_server = pp.Server(ncpus, ppservers=ppservers)
else:
# Creates jobserver with automatically detected number of workers
job_server = pp.Server(ppservers=ppservers)
print "pp 可以用的工作核心线程数", job_server.get_ncpus(), "workers"
start_time = time.time()
jobs = [(input, job_server.submit(SumPrimes,(input,), (IsPrime,), ("math",))) for input in inputs]#submit提交任务
for input, job in jobs:
print "Sum of primes below", input, "is", job()# job()获取方法执行结果
print "多线程下执行耗时: ", time.time() - start_time, "s"
job_server.print_stats()#输出执行信息
并行实例
http://blog.csdn.net/dai451954706/article/details/31399317
参考链接
并行:
http://blog.csdn.net/u013378306/article/details/72853750
http://blog.csdn.net/dai451954706/article/details/31399317
多线程:
http://rookiedong.iteye.com/blog/1186004
http://blog.csdn.net/pdcxs007/article/details/49813943
打印得例子在知乎上。。。百度应该可以百度的到。
相关理论:
http://blog.csdn.net/cskchenshengkun/article/details/45770627
还有百度知道。
我只是搬砖工,能点赞的希望点赞,么么哒。饿死了,去吃饭了