进程
进程:正在进行的一个过程或者说一个任务。而负责执行任务则是cpu
程序仅仅只是一堆代码而已,而进程指的是程序的运行过程。
一 并发:是伪并行,即看起来是同时运行。单个cpu+多道技术就可以实现并发,(并行也属于并发)
二 并行:同时运行,只有具备多个cpu才能实现并行
方式一:
from multiprocessing import Process
import time
def work(name):
print('task <%s> is runing' %name)
time.sleep(2)
print('task <%s> is done' % name)

if __name__ == '__main__':
# Process(target=work,kwargs={'name':'egon'})
p1=Process(target=work,args=('egon',))
p2=Process(target=work,args=('alex',))
p1.start()
p2.start()
print('主')
方式二:
from multiprocessing import Process
import time
class MyProcess(Process):
def __init__(self,name):
super().__init__()
self.name=name

def run(self):
print('task <%s> is runing' % self.name)
time.sleep(2)
print('task <%s> is done' % self.name)



if __name__ == '__main__':
p=MyProcess('egon')
p.start()

print('主')

守护进程:
from multiprocessing import Process
import time
def foo():
print(123)
time.sleep(1)
print("end123")

def bar():
print(456)
time.sleep(3)
print("end456")
if __name__ == '__main__':

p1=Process(target=foo)
p2=Process(target=bar)

p1.daemon=True
p1.start()
p2.start()
print("main-------") #打印该行则主进程代码结束,则守护进程p1应该被终止,可能会有p1任务执行的打印信息123,因为主进程打印main----时,p1也执行了,但是随即被终止

同步锁:
# from multiprocessing import Process,Lock
# import time
# def work(name,mutex):
# mutex.acquire()
# print('task <%s> is runing' %name)
# time.sleep(2)
# print('task <%s> is done' % name)
# mutex.release()
#
# if __name__ == '__main__':
# mutex=Lock()
# p1=Process(target=work,args=('egon',mutex))
# p2=Process(target=work,args=('alex',mutex))
# p1.start()
# p2.start()
# print('主')

队列:
from multiprocessing import Queue


# q=Queue(3)
#
# q.put('first')
# q.put('second')
# q.put('third')
# # q.put('fourth')
#
# print(q.get())
# print(q.get())
# print(q.get())
# print(q.get())




了解
q=Queue(3)

q.put('first',block=False)
q.put('second',block=False)
q.put('third',block=False)
# q.put_nowait('fourth') #q.put('fourth',block=False)
q.put('fourth',timeout=3)


paramiko:
import paramiko

transport = paramiko.Transport(('120.92.84.249', 22))
transport.connect(username='root', password='123QWEasd')

sftp = paramiko.SFTPClient.from_transport(transport)
# 将location.py 上传至服务器 /tmp/test.py
sftp.put('id_rsa', '/tmp/test.rsa')
# 将remove_path 下载到本地 local_path
# sftp.get('remove_path', 'local_path')

transport.close()

进程池:
import requests #pip3 install requests
import os,time
from multiprocessing import Pool
def get_page(url):
print('<%s> get :%s' %(os.getpid(),url))
respone = requests.get(url)
if respone.status_code == 200:
return {'url':url,'text':respone.text}

def parse_page(dic):
print('<%s> parse :%s' %(os.getpid(),dic['url']))
time.sleep(0.5)
res='url:%s size:%s\n' %(dic['url'],len(dic['text'])) #模拟解析网页内容
with open('db.txt','a') as f:
f.write(res)


if __name__ == '__main__':
p=Pool(4)
urls = [
'http://www.baidu.com',
'http://www.baidu.com',
'http://www.baidu.com',
'http://www.baidu.com',
'http://www.baidu.com',
'http://www.baidu.com',
'http://www.baidu.com',
]


for url in urls:
p.apply_async(get_page,args=(url,),callback=parse_page)


p.close()
p.join()
print('主进程pid:',os.getpid())



 
线程

在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程

线程顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程

多线程指的是,在一个进程中开启多个线程,简单的讲:如果多个任务共用一块地址空间,那么必须在一个进程内开启多个线程。详细的讲分为4点:

  1. 多线程共享一个进程的地址空间

      2. 线程比进程更轻量级,线程比进程更容易创建可撤销,在许多操作系统中,创建一个线程比创建一个进程要快10-100倍,在有大量线程需要动态和快速修改时,这一特性很有用

      3. 若多个线程都是cpu密集型的,那么并不能获得性能上的增强,但是如果存在大量的计算和大量的I/O处理,拥有多个线程允许这些活动彼此重叠运行,从而会加快程序执行的速度。

      4. 在多cpu系统中,为了最大限度的利用多核,可以开启多个线程,比开进程开销要小的多。(这一条并不适用于python)

 

线程:
一套流水线的运行过程,操作系统是个工厂,里面有有多个车间(进程),线程就是每个车间生产的流水线,每个进程,默认都会有个线程
进程是资源单元,线程是cpu上的调度单位
线程的创建开销小,共享空间
进程直接是竞争关系,线程之间是协作关系
 
 
一、线程的模块threading模块
方式一
from threading import Thread
from multiprocessing import Process
 
def task():
    print('is running')
 
if __name__ == '__main__':
    t=Thread(target=task,)#线程
    # t=Process(target=task,)#进程
    t.start()
    print('主’)
 
线程的结果:
is running
 
进程:
is running
进程开销大
线程开销小
 
方式二
from threading import Thread
from multiprocessing import Process
class MyThread(Thread):
    def __init__(self,name):
        super().__init__()
        self.name=name
    def run(self):
        print('%s is running' %self.name)
 
if __name__ == '__main__':
    t=MyThread('egon')
    # t=Process(target=task,)
    t.start()
    print('主’)
 
 
二、pid:
多线程的pid是一样的
多进程 pid不一样
 
三、多线程共享同一个进程内的资源:
from threading import Thread
from multiprocessing import Process
n=100
def work():
    global n
    n=0
 
if __name__ == '__main__':
 
    # p=Process(target=work,)
    # p.start()
    # p.join()
    # print('主',n)
 
    t=Thread(target=work,)
    t.start()
    t.join()
    print('主',n)
线程的n会变,进程不会。
因为线程共享资源,进程不是,而且进程pid不一样。
 
 
四、多线程共享同一进程内存地址空间:
from threading import Thread
msg_l=[]
format_l=[]
def talk():
    while True:
        msg=input('>>: ').strip()
        msg_l.append(msg)
 
def format():
    while True:
        if msg_l:
            data=msg_l.pop()
            format_l.append(data.upper())
 
def save():
    while True:
        if format_l:
            data=format_l.pop()
            with open('db.txt','a') as f:
                f.write('%s\n' %data)
 
if __name__ == '__main__':
    t1=Thread(target=talk)
    t2=Thread(target=format)
    t3=Thread(target=save)
 
    t1.start()
    t2.start()
    t3.start()
 
 
Threading其他方法:
#current_thread:当前的线程对象
from threading import Thread,activeCount,enumerate,current_thread
import time
def task():
    print('%s is running' %current_thread().getName())
    time.sleep(2)
 
if __name__ == '__main__':
    t=Thread(target=task,)
    t.start()
    t.join()#等待task运行结束(系统回收完)
    print(t.is_alive())#返回线程是否活动
    print(t.getName())#返回线程名
    print(enumerate())#当前活跃的进程对象
    print('主')
    print(activeCount())#活着的线程数
 
主线程从执行层面上代表了,其所在进程的执行过程。
 
 
五、守护线程
无论是进程还是线程,都遵循:守护会等待主运行完毕后被销毁
需要强调的是:运行完毕并非终止运行
from threading import Thread
import time
 
def task1():
    print('123')
    time.sleep(10)
    print('123done')
 
def task2():
    print('456')
    time.sleep(1)
    print('456done')
 
if __name__ == '__main__':
    t1=Thread(target=task1)
    t2=Thread(target=task2)
    t1.daemon=True
    t1.start()
    t2.start()
    print('主’)
 
六、GIL

三个需要注意的点:
1.线程抢的是GIL锁,GIL锁相当于执行权限,拿到执行权限后才能拿到互斥锁Lock,其他线程也可以抢到GIL,但如果发现Lock仍然没有被释放则阻塞,即便是拿到执行权限GIL也要立刻交出来

2.join是等待所有,即整体串行,而锁只是锁住修改共享数据的部分,即部分串行,要想保证数据安全的根本原理在于让并发变成串行,join与互斥锁都可以实现,毫无疑问,互斥锁的部分串行效率要更高

线程1抢到GIL锁,拿到执行权限,开始执行,然后加了一把Lock,还没有执行完毕,即线程1还未释放Lock,有可能线程2抢到GIL锁,开始执行,执行过程中发现Lock还没有被线程1释放,于是线程2进入阻塞,被夺走执行权限,有可能线程1拿到GIL,然后正常执行到释放Lock。。。这就导致了串行运行的效果

七、互斥锁
from threading import Thread,Lock
import time
n=100
def work():
time.sleep(0.05)
global n
mutex.acquire()
temp=n
time.sleep(0.1)
n=temp-1
mutex.release()

if __name__ == '__main__':
mutex=Lock()
l=[]
start=time.time()
for i in range(100):
t=Thread(target=work)
l.append(t)
t.start()

for t in l:
t.join()
print('run time:%s value:%s' %(time.time()-start,n))


#多进程:
#优点:可以利用多核优势
#缺点:开销大


#多线程:
#优点:开销小
#缺点:不能利用多核优势

# from threading import Thread
# from multiprocessing import Process
# import time
# #计算密集型
# def work():
# res=1
# for i in range(100000000):
# res+=i
#
# if __name__ == '__main__':
# p_l=[]
# start=time.time()
# for i in range(4):
# # p=Process(target=work) #6.7473859786987305
# p=Thread(target=work) #24.466399431228638
# p_l.append(p)
# p.start()
# for p in p_l:
# p.join()
#
# print(time.time()-start)


from threading import Thread
from multiprocessing import Process
import time
#IO密集型
def work():
time.sleep(2)

if __name__ == '__main__':
p_l=[]
start=time.time()
for i in range(400):
# p=Process(target=work) #12.104692220687866
p=Thread(target=work) #2.038116455078125
p_l.append(p)
p.start()
for p in p_l:
p.join()

print(time.time()-start)

八、死锁与递归锁
所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁
死锁现象
from threading import Thread,Lock,RLock
import time
mutexA=Lock()
mutexB=Lock()
class Mythread(Thread):
def run(self):
self.f1()
self.f2()

def f1(self):
mutexA.acquire()
print('\033[45m%s 抢到A锁\033[0m' %self.name)
mutexB.acquire()
print('\033[44m%s 抢到B锁\033[0m' %self.name)
mutexB.release()
mutexA.release()

def f2(self):
mutexB.acquire()
print('\033[44m%s 抢到B锁\033[0m' %self.name)
time.sleep(1)
mutexA.acquire()
print('\033[45m%s 抢到A锁\033[0m' %self.name)
mutexA.release()
mutexB.release()


if __name__ == '__main__':
for i in range(20):
t=Mythread()
t.start()

递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。

这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁

#递归锁
from threading import Thread,Lock,RLock
import time
mutex=RLock()
class Mythread(Thread):
def run(self):
self.f1()
self.f2()

def f1(self):
mutex.acquire()
print('\033[45m%s 抢到A锁\033[0m' %self.name)
mutex.acquire()
print('\033[44m%s 抢到B锁\033[0m' %self.name)
mutex.release()
mutex.release()

def f2(self):
mutex.acquire()
print('\033[44m%s 抢到B锁\033[0m' %self.name)
time.sleep(1)
mutex.acquire()
print('\033[45m%s 抢到A锁\033[0m' %self.name)
mutex.release()
mutex.release()


if __name__ == '__main__':
for i in range(20):
t=Mythread()
t.start()
 
九、信号量
from threading import Thread,current_thread,Semaphore
import time,random

sm=Semaphore(5)
def work():
sm.acquire()
print('%s 上厕所' %current_thread().getName())
time.sleep(random.randint(1,3))
sm.release()

if __name__ == '__main__':
for i in range(20):
t=Thread(target=work)
t.start()
posted on 2018-02-08 21:53  小白凹凸曼  阅读(101)  评论(0编辑  收藏  举报