Python-多线程与并行计算

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
还有百度知道。
我只是搬砖工,能点赞的希望点赞,么么哒。饿死了,去吃饭了




你可能感兴趣的:(Python)