python多线程

一、线程&进程

摘自:http://www.nnzhp.cn/archives/135

对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程,打开一个Word就启动了一个Word进程。进程是很多资源的集合。

 有些进程还不止同时干一件事,比如Word,它可以同时进行打字、拼写检查、打印等事情。在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程(Thread)。

由于每个进程至少要干一件事,所以,一个进程至少有一个线程。当然,像Word这种复杂的进程可以有多个线程,多个线程可以同时执行,多线程的执行方式和多进程是一样的,也是由操作系统在多个线程之间快速切换,让每个线程都短暂地交替运行,看起来就像同时执行一样。当然,真正地同时执行多线程需要多核CPU才可能实现。线程是最小的执行单元,而进程由至少一个线程组成。

我们在做事情的时候,一个人做是比较慢的,如果多个人一起来做的话,就比较快了,程序也是一样的,我们想运行的速度快一点的话,就得使用多进程,或者多线程,在python里面,多线程被很多人诟病,为什么呢,因为Python的解释器使用了GIL的一个叫全局解释器锁,它不能利用多核CPU,只能运行在一个cpu上面,但是你在运行程序的时候,看起来好像还是在一起运行的,是因为操作系统轮流让各个任务交替执行,任务1执行0.01秒,切换到任务2,任务2执行0.01秒,再切换到任务3,执行0.01秒……这样反复执行下去。表面上看,每个任务都是交替执行的,但是,由于CPU的执行速度实在是太快了,我们感觉就像所有任务都在同时执行一样。这个叫做上下文切换。

二、多线程

下面是一个简单的多线程例子

import threading
import time

def abc(count):
    time.sleep(5)
    print(count)


for i in range(10):
    t = threading.Thread(target=abc,args=(i,))#实例化一个线程,启动一个线程
    t.start()
print('game over')

简单的爬虫,看下多线程的效果

import requests, threading, time

urls = ['http://www.nnzhp.cn', 'http://www.besttest.cn/', 'http://www.imdsx.cn/', 'http://sb.nnzhp.cn/dashboard/',
        'http://bbs.besttest.cn/', 'http://video.besttest.cn/']


def write_html(url, name):
    req = requests.get(url)
    with open(name, 'w', encoding='utf-8') as f:
        f.write(req.text)

threads = []
def bx():
    starttime1 = time.time()
    for i in range(6):
        t = threading.Thread(target=write_html, args=(urls[i], str(i),))  # 实例化一个线程,启动一个线程
        threads.append(t)
        t.start()
    for thread in threads:
        thread.join()
    endtime1 = time.time()
    return endtime1 - starttime1
print('并行时间',bx())

再来看看串行运行的时间

def cx():
    starttime2 = time.time()
    for i in range(6):
        write_html(urls[i], str(i))
    endtime2 = time.time()
    return endtime2 - starttime2
print('串行时间',cx())

多线程较单线程时减少了2秒 。

线程等待:上面的例子中用到了.join(),用于等待线程终止。在子线程完成运行之前,这个子线程的父线程将一直被阻塞。

守护线程:setDaemon(True)将线程声明为守护线程,如果在程序中将子线程设置为守护线程,则该子线程会在主线程结束时自动退出。

如果你设置一个线程为守护线程,就表示你在说这个线程是不重要的,在进程退出的时候,不用等待这个线程退出。如果你的主线程在退出的时候,不用等待那些子线程完成,那就设置这些线程的daemon属性。

线程锁:线程锁就是,很多线程一起在操作一个数据的时候,可能会有问题,就要把这个数据加个锁,同一时间只能有一个线程操作这个数据。

import threading

lock = threading.Lock()#申请一把锁
a = 0


def test():
    global a
    lock.acquire()#加锁
    a += 1
    lock.release()#解锁


threads = []
for i in range(1000):
    t = threading.Thread(target=test)
    t.start()
    threads.append(t)
for t in threads:
    t.join()
print('over', a)

三、多进程,Python里面的多线程,是不能利用多核CPU的,如果想利用多核CPU的话,就得使用多进程,python中多进程使用multiprocessing模块。

from multiprocessing import Process
import time


def sayHello(name):
    time.sleep(2)
    print('hello', name)


p = Process(target=sayHello, args=('abc',))
p.start()
p.join() 

 

posted @ 2017-12-02 17:53  nagisaling  阅读(145)  评论(0)    收藏  举报