python全栈学习--day41(线程概念,线程的特点,进程和线程的关系,线程和python 理论知识,线程的创建)

 队列

  队列:先进先出,数据进程安全

  管道 + 锁

  生产者消费者模型:解决数据供需不平衡

多个进程取值,不会发生数据不一致。数据进程安全

队列实现方式是 管道 + 锁

管道

  双向通信  数据进程不安全

  EOFError:

    管道是由操作系统进行引用计数的。

    必须在所有进程中关闭管道后才能生成EOFError 异常

管道和数据共享,数据是不安全的。

数据共享(不常用)

  Manager

  list dict 数据进程不安全的

队列是内置锁,所以别的应用调用它,是安全的。

凡是涉及到手动加锁的,都是不安全的。常用的一般都是消息中间件

进程池:

  存放进程的容器

  在进程创建之初,创建固定个数的进程在执行

  会被多个任务循环利用

  节省了进程创建和销毁的时间开销

  降低了操作系统调度进程的压力

信号量和进程池的区别

  信号量n个任务开启n个进程。

    但同一时间只能有固定个数的进程在执行

  进程池 n 个任务开启固定个数的进程

    因此同一时间只能有固定个数的进程在执行

例如:200个任务--200个进程 4个进程执行 信号量

    200个任务--4个进程  4个进程执行 进程池

一个进程是等待,一个是任务等待。

信号量 n 个任务开启n个进程。

  但同一时间只能有固定个数的进程在执行

  进程在等待被执行

进程池 n 任务开启固定个数的进程

  因此同一时间只能有固定个数的进程在执行

  任务在等待被执行

import time
from multiprocessing import Pool
def wahaha(i):
    time.sleep(1)
    print('*'*i)
if  __name__ == "__main__":
    p  =  Pool(5)
    p.map(func=wahaha,iterable=range(10))
实例源码

说明:

自带close和join

但是参数必须是一个iterable

不能获取返回值

import time
from multiprocessing import Pool
def wahaha(i):
    time.sleep(1)
    print('*'*i)
if  __name__ == "__main__":
    p  =  Pool(5)
    p.map(func=wahaha,iterable=range(10))

    res_l = []
    for i in range(10):
        res = p.apply_async(func=wahaha,args=[i,])
        res_l.append(res)
    for i in res_l:print(i.get())
    p.close()     # 不能再提交新的任务
    p.join()      #等待池中的任务都执行完

 

*
**
***
****
******
*****
*******
********
*********

*
***
**
None
None
None
None
****
None
******
*****
None
None
********
*********
*******
None
None
None

主进程默认等待子进程结束----守护进程

普通的进程:根据你调用的函数执行结束它就结束了

进程池里的进程

   没有返回值

      在提交任务之后:

      p.close()  #不能在提交新的任务

      p.join()  #等待池中的任务都执行完

    有返回值的时候:

      在提交任务之后:

      

for i in res_l:print(i.get())

回调函数

  回调函数在什么时候执行

    子进程的任务执行完毕以后立即触发

  回调函数的参数

    子进程的返回值

  回调函数是由谁执行的

    主进程执行的

  在哪儿用?

    爬虫:

      如果要爬取多个格式相同的网页

      真正影响程序效率的是网络的延迟

      计算 分析 处理网页的时间是很快的

#500

  有回调函数

  没有回调函数快

进程:操作系统管理进程,进程是执行任务,资源的隔离。在一个操作系统中,同一时间,有多个任务。多个任务之间的内存必须隔离开。使用QQ的时候,还能使用微信

并发

并发的要求日益增加,聊天----开子进程。你可以看电影-----开子进程,缓存其他电影。开启一个子进程的开销,是很大的。操作系统在进程之间的切换 ,时间开销也很大。

 

进程之间的通信

数据共享:时间开销

如果多个子进程之间的数据共享量过多的时候,就不应该将这些数据隔离开。一个进程-----实现不了并发。

你既不希望数据隔离,还要实现并发的效果。

 

线程

线程是轻量级的进程,线程的创建和销毁所需要的时间开销都非常小,线程直接使用进程的内存,线程不能独立存在,要依赖于进程。

 

进程---资源分配的最小单位

线程---CPU调度的最小单位

  轻型进程:创建、销毁、切换、开销比进程小

  数据不隔离

  可以并发

  依赖进程

每一个进程里至少有一个线程,进程负责资源、线程负责执行代码。

python程序运行起来------进程

进程-----管理整个程序的内存。

  存储全局的变量:内置的函数  全局的名字

线程-----执行代码

利用python开启多线程---------并发

import os
import time
from threading import Thread
from multiprocessing import Process
def func(i):
    print('---->',os.getppid())
    time.sleep(1)
    print('*',i)

if __name__=='__main__':
    print(os.getppid())
    start = time.time()
    thread_lst = []
    for i in range(20):
        t = Thread(target=func,args=(i,))
        t.start()
        print('---->',t.name,t.ident)
        thread_lst.append(t)
    for t in thread_lst:t.join()
    print(time.time()-start)

    start = time.time()
    process_lst = []
    for i in range(20):
        p = Process(target=func,args=(i,))
        p.start()
        process_lst.append(p)
    for p in process_lst:p.join()
    print(time.time()-start)

  执行输出:

3624
----> 3624
----> Thread-1 2168
----> Thread-2 1600
----> 3624
----> 3624
----> Thread-3 13856
----> 3624
----> Thread-4 6100
----> 3624
----> Thread-5 3712
----> 3624
----> Thread-6 14408
----> 3624
----> Thread-7 4480
----> 3624
----> Thread-8 3760
----> 3624
----> Thread-9 16268
----> Thread-10 11848
----> 3624
----> Thread-11 4244
----> 3624
----> Thread-12 13804
----> 3624
----> Thread-13 5788
----> 3624
----> Thread-14 1028
----> 3624
----> Thread-15 6608
----> 3624
----> Thread-16 15312
----> 3624
----> Thread-17 14580
----> 3624
----> Thread-18 6564
----> 3624
----> Thread-19 11672
----> 3624
----> Thread-20 11396
----> 3624
* 0
* 1
* 2
* 3
* 4
* 5
* 6
* 7
* 8
* 9
* 10
* 11
* 12
* 13
* 14
* 15
* 16
* 17
* 18
* 19
1.107273817062378
----> 4468
----> 4468
----> 4468
----> 4468
----> 4468
----> 4468
----> 4468
----> 4468
----> 4468
----> 4468
----> 4468
----> 4468
----> 4468
----> 4468
----> 4468
----> 4468
----> 4468
----> 4468
----> 4468
----> 4468
* 0
* 1
* 3
* 2
* 4
* 5
* 6
* 7
* 9
* 8
* 10
* 11
* 15
* 12
* 13
* 16
* 14
* 18
* 17
* 19
1.9786567687988281

效率问题:线程快 进程慢

同一个进程下的多个线程进程号相同:线程号不同

if __name__ == '__main__' : 开启进程 必须有这句话 但是开启线程不需要
这种现象只在windows操作系统上才出现


数据的共享问题:在进程之间数据隔离,在线程之间数据共享

def manager():
    global n
from threading import Thread
n = 100
t = Thread(target=manager)
t.start()
t.join()
print('-------->',n)

 

GIL —— 全局解释器锁

锁线程 :在计算的时候 同一时刻只能有一个线程访问CPU

线程锁限制了你对CPU的使用,但是不影响web类或者爬虫类代码的效率

我们可以通过启动多进程的形式来弥补这个问题

import time
from threading import Thread
def func1():
    while True:
        time.sleep(1)
        print('子线程')

def func2():
    time.sleep(5)
    print('子线程2')

t = Thread(target=func1)
t2 = Thread(target=func2)
t.setDaemon(True)
t.start()
t2.start()
print('主线程')
守护线程

# 主进程的守护进程是在主进程的代码结束,守护进程就结束了
# 主线程的守护线程会在非守护线程的所有线程执行完毕之后才结束

posted @ 2018-05-15 17:11  John966  阅读(136)  评论(0编辑  收藏  举报