【澳门葡京备用网址】第玖①篇,多线程与MySQL

1.1 多线程

在价值观操作系统中,每种进度有三个地点空间,而且暗许就有一个垄断线程

  线程顾名思义,便是一条流水生产线专门的学业的长河,一条流水生产线必须属于三个车间,3个车间的专门的学业进度是2个进度

   
车间肩负把能源整合到3头,是三个财富单位,而2个车间内至少有3个流水生产线

    流水生产线的办事急需电源,电源就也正是cpu

  所以,进度只是用来把资源聚集到三头(进程只是一个财富单位,可能说能源会集),而线程才是cpu上的执行单位。

  10②线程(即七个控制线程)的定义是,在叁个历程中设有多个调整线程,多少个调节线程共享该进程的地方空间,也就是3个车间内有多条流水生产线,都共用贰个车间的能源。

    
比方,东京客车与东京大巴是例外的历程,而巴黎地铁里的一三号线是三个线程,香岛大巴全体的路线共享东京客车全体的财富,比如存有的司乘职员得以被抱有线路拉。

l  创制进度的开支要远超过线程?

即使大家的软件是一个工厂,该工厂有多条流水生产线,流水生产线职业亟待电源,电源唯有三个即cpu(单核cpu),一个车间正是二个进度,二个车间至少一条流水生产线(3个经过至少二个线程),创设1个历程,正是创办三个车间(申请空间,在该空间内建最少一条流水生产线),而建线程,就只是在3个车间内造一条流水生产线,无需申请空间,所以创造开支小

l  进程之间是竞争关系,线程之间是同盟关系?

车间直接是竞争/抢电源的涉嫌,竞争(分化的长河一直是竞争关系,是不相同的程序员写的程序运维的,迅雷抢占其余进度的网速,360把此外进程作为病毒干死),三个车间的不及流水生产线式协同专门的学问的涉及(同二个进程的线程之间是合作关系,是同1个先后写的程序内开运转,迅雷内的线程是同盟关系,不会和谐干本身)

102线程与MySQL(拾),10贰线程MySQL(

1、进度和线程的概念

读书目录

一. cpython并发编制程序之多进度
壹.1 multiprocessing模块介绍
1.二 Process类的牵线
一.三 Process类的使用
一.四 进程间通讯(IPC)格局1:队列
壹.5 进程间通讯(IPC)格局二:管道(精晓一些)
一.陆 进度间通讯方式三:共享数据
一.7 进度同步(锁),实信号量,事件…
1.8 进程池
二. python并发编制程序之八线程
2.1 threading模块
2.2 Python GIL(Global Interpreter Lock)
2.3 同步锁
贰.四 死锁与递归锁
2.5 信号量Semahpore
2.6 事件Event
2.7 条件Condition(了解)

2.8 定时器Timer
2.9 线程queue
2.十 Python规范模块–concurrent.futures
三.  协程

四. 协程模块greenlet

5. gevent模块(单线程并发)

6. 综合使用

 

一.1.一 为什么要用四线程

  10贰线程指的是,在1个经过中打开四个线程,简单来讲:假若几个职分共用壹块地方空间,那么必须在三个进度内展开多少个线程。详细的讲分为四点:

  一. 多线程共享二个历程的地点空间

    二.
线程比进度更轻量级,线程比进度更易于创立可裁撤,在重重操作系统中,创造2个线程比创设三个进度要快10-十0倍,在有大气线程要求动态和急速修改时,那一风味很有用

    3.
若七个线程都以cpu密集型的,那么并无法赢得属性上的进步,可是假若存在大气的计量和大批量的I/O管理,具备多少个线程允许那个活动竞相臃肿运转,从而会加速程序实行的快慢。

四.
在多cpu系统中,为了最大限度的选用多核,能够张开多个线程,比开进度花费要小的多。(这一条并不适用于python)

 

 

 

1.1 多线程

【澳门葡京备用网址】第玖①篇,多线程与MySQL。在守旧操作系统中,各样进度有3个地址空间,而且暗中同意就有2个调整线程

  线程顾名思义,就是一条流水生产线职业的长河,一条流水生产线必须属于多个车间,二个车间的干活历程是一个进度

   
车间担任把能源整合到一起,是三个资源单位,而一个车间内至少有多个流程

    流水生产线的行事索重要电报源,电源就一定于cpu

  所以,进度只是用来把能源集中到一道(进度只是3个财富单位,只怕说资源聚焦),而线程才是cpu上的实行单位。

  八线程(即三个调整线程)的定义是,在3个历程中设有七个调整线程,多少个调节线程共享该进度的地址空间,也就是二个车间内有多条流水生产线,都共用2个车间的财富。

    
比如,东京(Tokyo)大巴与新加坡地铁是见仁见智的进度,而新加坡客车里的1三号线是3个线程,上海大巴全数的路径共享东京(Tokyo)大巴全数的能源,比方存有的司乘职员得以被抱无线路拉。

l  成立进程的支付要远不止线程?

假诺大家的软件是3个厂子,该工厂有多条流水生产线,流水生产线职业急需电源,电源唯有三个即cpu(单核cpu),二个车间就是二个进程,一个车间至少一条流水生产线(1个经过至少1个线程),创立八个进程,正是创立一个车间(申请空间,在该空间内建至少一条流水生产线),而建线程,就只是在三个车间内造一条流水生产线,无需申请空间,所以创设开销小

l  进度之间是竞争关系,线程之间是协作关系?

车间直接是竞争/抢电源的关联,竞争(分歧的进度一贯是竞争关系,是不相同的程序员写的程序运维的,迅雷抢占其余进度的网速,360把其他进程作为病毒干死),3个车间的差异流水生产线式协同事业的关系(同一个历程的线程之间是合作关系,是同一个程序写的顺序内开运行,迅雷内的线程是同盟关系,不会友善干本身)

率先,引出“多职责”的概念:多职分管理是指用户可以在同一时间内运营多少个应用程序,每种应用程序被称作2个职务。Linux、windows就是永葆多义务的操作系统,比起单职责系统它的效能巩固了广大。

壹. cpython并发编制程序之多进度

一.2 死锁现象与递归锁

进度也有死锁与递归锁。

所谓死锁:
是指八个或多少个以上的进度或线程在奉行进度中,因争夺财富而致使的1种互动等待的景观,若无外力作用,它们都将不能推进下去。此时称系统处于死锁状态或系统产生了死锁,那一个恒久在互相等待的经过称为死锁进程。

 
递归锁,在Python中为了帮助在同1线程中屡屡呼吁同一财富,python提供了可重入锁昂CoraLock,

本条奥迪Q3Lock内部维护着一个Lock和三个counter变量,counter记录了acquire的次数,从而使得财富得以被频仍require。直到二个线程全体的acquire都被release,别的的线程技能博得财富。上面包车型大巴事举例果使用福睿斯Lock替代Lock,则不会发生死锁:

 

from threading import Thread,Lock,RLock

import time



# mutexA=Lock()

# mutexB=Lock()



mutexA=mutexB=RLock()  #一个线程拿到锁,counter加1,该线程内又碰到加锁的情况,则counter继续加1,这期间所有其他线程都只能等待,等待该线程释放所有锁,即counter递减到0为止



class MyThread(Thread):

    def run(self):

        self.f1()

        self.f2()



    def f1(self):

        mutexA.acquire()

        print('%s 拿到了A锁' %self.name)



        mutexB.acquire()

        print('%s 拿到了B锁' % self.name)

        mutexB.release() #1



        mutexA.release() #0



    def f2(self):

        mutexB.acquire()

        print('%s 拿到了B锁' % self.name)

        time.sleep(0.1)



        mutexA.acquire()

        print('%s 拿到了A锁' % self.name)

        mutexA.release()



        mutexB.release()







if __name__ == '__main__':

    for i in range(10):

        t=MyThread()

        t.start()

 

 

一.一.一 为啥要用十二线程

  八线程指的是,在三个进度中拉开五个线程,简单的说:借使多个职务共用一块地点空间,那么必须在一个进程内张开四个线程。详细的讲分为四点:

  1. 四线程共享2个经过的地方空间

    二.
线程比进程更轻量级,线程比进度更便于成立可打消,在大多操作系统中,创造三个线程比成立3个进度要快10-十0倍,在有雅量线程须要动态和快速修改时,那1特色很有用

    3.
若五个线程都以cpu密集型的,那么并不能够收获属性上的加强,不过如若存在多量的企图和大量的I/O管理,拥有八个线程允许那些移动互动臃肿运转,从而会加速程序推行的速度。

4.
在多cpu系统中,为了最大限度的应用多核,能够拉开四个线程,比开进程费用要小的多。(这一条并不适用于python)

 

 

 

譬如说,你一只在用浏览器上网,一边在听新浪云音乐,一边在用Word赶作业,那就是多职责,至少还要有二个义务正在运行。还有众多职分悄悄地在后台同时运转着,只是桌面上未有呈现而已。

壹.1 multiprocessing模块介绍

python中的多线程无法利用多核优势,借使想要充足地动用多核CPU的能源(os.cpu_count()查看),在python中山大学部情状供给选用多进度。Python提供了丰硕好用的多进程包multiprocessing。
 multiprocessing模块用来开启子进度,并在子进度中进行大家定制的职务(举例函数),该模块与10贰线程模块threading的编制程序接口类似。

multiprocessing模块的机能多多:帮衬子进度、通讯和共享数据、推行不相同式样的三头,提供了Process、Queue、Pipe、Lock等零件。

强调:
与线程不一致,进度未有其余共享状态,进程修改的数额,更改只限于该进度内。

1.3 信号量Semaphore

同进度的平等,Semaphore管理3个内置的计数器,每当调用acquire()时内置计数器-壹;调用release()
时内置计数器+壹;计数器无法小于0;当计数器为0时,acquire()将阻塞线程直到别的线程调用release()。

实例:(同时唯有多少个线程能够收获semaphore,即能够界定最辛辛那提接数为五):

from threading import Thread,Semaphore,current_thread

import time,random



sm=Semaphore(5)



def task():

    with sm:

        print('%s is laing' %current_thread().getName())

        time.sleep(random.randint(1,3))



if __name__ == '__main__':

    for i in range(20):

        t=Thread(target=task)

        t.start()

 

与进度池是一点1滴不一致的概念,进程池Pool(四),最大不得不发出几个进程,而且从头到尾都只是那两个经过,不会发出新的,而连续信号量是发生一群线程/进度

一.2 死锁现象与递归锁

进程也有死锁与递归锁。

所谓死锁:
是指七个或七个以上的长河或线程在实践进度中,因争夺财富而致使的1种相互等待的情景,若无外力作用,它们都将不能够推进下去。此时称系统处于死锁状态或系列发生了死锁,这么些永久在互动等待的进度称为死锁进度。

 
递归锁,在Python中为了援助在同1线程中频仍请求同一财富,python提供了可重入锁奥迪Q5Lock,

这么些LacrosseLock内部维护着2个Lock和一个counter变量,counter记录了acquire的次数,从而使得财富可以被一再require。直到多个线程全体的acquire都被release,别的的线程手艺赢得能源。上边的例证若是选取索罗德Lock替代Lock,则不会产生死锁:

 

from threading import Thread,Lock,RLock

import time



# mutexA=Lock()

# mutexB=Lock()



mutexA=mutexB=RLock()  #一个线程拿到锁,counter加1,该线程内又碰到加锁的情况,则counter继续加1,这期间所有其他线程都只能等待,等待该线程释放所有锁,即counter递减到0为止



class MyThread(Thread):

    def run(self):

        self.f1()

        self.f2()



    def f1(self):

        mutexA.acquire()

        print('%s 拿到了A锁' %self.name)



        mutexB.acquire()

        print('%s 拿到了B锁' % self.name)

        mutexB.release() #1



        mutexA.release() #0



    def f2(self):

        mutexB.acquire()

        print('%s 拿到了B锁' % self.name)

        time.sleep(0.1)



        mutexA.acquire()

        print('%s 拿到了A锁' % self.name)

        mutexA.release()



        mutexB.release()







if __name__ == '__main__':

    for i in range(10):

        t=MyThread()

        t.start()

 

 

可是,那么些职务是还要在运转着的吧?颇负盛名,运维2个职分就必要cpu去处理,那还要运营三个职务就必须要求多少个cpu?那要是有九十七个职责供给同时运营,就得买一个十0核的cpu吗?明显不可能!

壹.二 Process类的牵线

开创进度的类:

Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化得到的对象,表示一个子进程中的任务(尚未启动)

强调:
1. 需要使用关键字的方式来指定参数
2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号

参数介绍:

group参数未使用,值始终为None

target表示调用对象,即子进程要执行的任务

args表示调用对象的位置参数元组,args=(1,2,'egon',)

kwargs表示调用对象的字典,kwargs={'name':'egon','age':18}

name为子进程的名称

方法介绍:

p.start():启动进程,并调用该子进程中的p.run() 
p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法  

p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁
p.is_alive():如果p仍然运行,返回True

p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程

质量介绍:

p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置

p.name:进程的名称

p.pid:进程的pid

p.exitcode:进程在运行时为None、如果为–N,表示被信号N结束(了解即可)

p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功(了解即可)

 

1.4 Event事件

同进度的1致,线程的四个要害天性是各个线程都以单身运行且景况不行预测。假如程序中的其他线程必要经过剖断有个别线程的情景来规定本身下一步的操作,这时线程同步难题就会变得卓殊吃力。为了消除那个题目,大家需求接纳threading库中的伊夫nt对象。
对象涵盖1个可由线程设置的功率信号标识,它同意线程等待某个事件的产生。在
开始景况下,伊夫nt对象中的非时域信号标识被安装为假。借使无线程等待2个伊夫nt对象,
而这么些伊芙nt对象的表明为假,那么这一个线程将会被直接不通直至该标识为真。贰个线程倘诺将一个伊芙nt对象的功率信号标记设置为真,它将唤起全数等待那一个伊夫nt对象的线程。假诺三个线程等待3个曾经棉被服装置为真正伊夫nt对象,那么它将忽略那一个事件,
继续施行

event.isSet():返回event的状态值;



event.wait():如果 event.isSet()==False将阻塞线程;



event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;



event.clear():恢复event的状态值为False。

 

譬如说,有八个专门的职业线程尝试链接MySQL,大家想要在链接前有限帮衬MySQL服务符合规律才让那二个职业线程去老是MySQL服务器,假若老是不成事,都会去尝尝再度连接。那么我们就可以行使threading.伊夫nt机制来和煦种种专业线程的连年操作

from threading import Thread,Event,current_thread

import time



event=Event()



def check():

    print('checking MySQL...')

    time.sleep(5)

    event.set()



def conn():

    count=1

    while not event.is_set():

        if count > 3:

            raise TimeoutError('超时')

        print('%s try to connect MySQL time %s' %(current_thread().getName(),count))

        event.wait(1)

        count+=1



    print('%s connected MySQL' %current_thread().getName())



if __name__ == '__main__':

    t1=Thread(target=check)

    t2=Thread(target=conn)

    t3=Thread(target=conn)

    t4=Thread(target=conn)





    t1.start()

    t2.start()

    t3.start()

    t4.start()

 

 

1.3 信号量Semaphore

同进度的同样,Semaphore管理三个内置的计数器,每当调用acquire()时内置计数器-一;调用release()
时内置计数器+1;计数器不可能小于0;当计数器为0时,acquire()将封堵线程直到其余线程调用release()。

实例:(同时只有四个线程能够收获semaphore,即能够界定最奥斯汀接数为五):

from threading import Thread,Semaphore,current_thread

import time,random



sm=Semaphore(5)



def task():

    with sm:

        print('%s is laing' %current_thread().getName())

        time.sleep(random.randint(1,3))



if __name__ == '__main__':

    for i in range(20):

        t=Thread(target=task)

        t.start()

 

与进程池是一点一滴不相同的定义,进程池Pool(肆),最大不得不发出五个经过,而且从头到尾都只是这七个进程,不会发出新的,而时域信号量是发生一群线程/进度

近日,多核CPU已经充足广泛了,可是,固然过去的单核CPU,也能够施行多职责。由于CPU施行代码都是逐1实施的,那么,单核CPU是怎么实践多任务的呢?

一.叁 Process类的施用

1.5 定时器

定时器,钦命n秒后施行某操作

from threading import Timer





def hello(name):

    print("hello, world %s " %name)





t = Timer(3, hello,args=('egon',))

t.start()  # after 1 seconds, "hello, world" will be printed

 

 

1.4 Event事件

同进度的平等,线程的3个根本本性是每一个线程都是独立运维且景况不行预测。借使程序中的别的线程须求通过剖断有个别线程的动静来规定自身下一步的操作,那时线程同步难题就会变得可怜费劲。为了化解这个主题材料,大家须要动用threading库中的伊芙nt对象。
对象涵盖多个可由线程设置的随机信号标识,它同意线程等待有个别事件的爆发。在
初阶意况下,伊夫nt对象中的复信号标记被设置为假。假若无线程等待一个伊芙nt对象,
而这几个伊夫nt对象的标记为假,那么这些线程将会被一直不通直至该标识为真。二个线程假若将三个伊夫nt对象的功率信号标识设置为真,它将唤起全体等待这么些伊夫nt对象的线程。倘使二个线程等待3个早已被安装为确实伊芙nt对象,那么它将忽略那一个事件,
继续实践

event.isSet():返回event的状态值;



event.wait():如果 event.isSet()==False将阻塞线程;



event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;



event.clear():恢复event的状态值为False。

 

比方,有八个办事线程尝试链接MySQL,大家想要在链接前确定保证MySQL服务平日才让那个工作线程去老是MySQL服务器,纵然连接不成功,都会去品尝重新连接。那么大家就能够利用threading.伊芙nt机制来和睦各样职业线程的总是操作

from threading import Thread,Event,current_thread

import time



event=Event()



def check():

    print('checking MySQL...')

    time.sleep(5)

    event.set()



def conn():

    count=1

    while not event.is_set():

        if count > 3:

            raise TimeoutError('超时')

        print('%s try to connect MySQL time %s' %(current_thread().getName(),count))

        event.wait(1)

        count+=1



    print('%s connected MySQL' %current_thread().getName())



if __name__ == '__main__':

    t1=Thread(target=check)

    t2=Thread(target=conn)

    t3=Thread(target=conn)

    t4=Thread(target=conn)





    t1.start()

    t2.start()

    t3.start()

    t4.start()

 

 

答案就是操作系统轮流让各种任务交替试行,职责1施行0.0一秒,切换成职责贰,职务2实行0.0一秒,再切换来职务叁,推行0.0壹秒……那样频仍实行下去。表面上看,各类职责都是轮番施行的,不过,由于CPU的实践进程其实是太快了,大家备感就如拥有任务都在同时实行同1。

1.成立并开启子进度的二种艺术

注:
在windows中Process()必须置于# if __name__ == ‘__main__’:下

Since Windows has no fork, the multiprocessing module starts a new
Python process and imports the calling module. 
If Process() gets called upon import, then this sets off an infinite
succession of new processes (or until your machine runs out of
resources). 
This is the reason for hiding calls to Process() inside

if __name__ == “__main__”
since statements inside this if-statement will not get called upon
import.

由于Windows未有fork,多管理模块运转1个新的Python进度并导入调用模块。 
要是在导入时调用Process(),那么那将起动Infiniti承接的新历程(或直到机器耗尽能源)。 
那是隐匿对Process()内部调用的规律,使用if __name__ == “__main
__”,那一个if语句中的语句将不会在导入时被调用。

澳门葡京备用网址 1澳门葡京备用网址 2

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# __author__ = "shuke"
# Date: 2017/6/26 0026

import time
import random
from multiprocessing import Process


def talk(name):
    print("%s is say 'Hello'" % name)
    time.sleep(3)
    print("talking end")

if __name__ == '__main__':
    p1=Process(target=talk,args=('Shuke',))         # args是元组的形式,必须加逗号
    p2=Process(target=talk,args=('Tom',))
    p3=Process(target=talk,args=('Eric',))
    p4=Process(target=talk,args=('Lucy',))
    p1.start()
    p2.start()
    p3.start()
    p4.start()

翻开过程(格局一)

澳门葡京备用网址 3澳门葡京备用网址 4

import time
import random
from multiprocessing import Process


class Talk(Process):    # 继承Process类

    def __init__(self,name):
        super(Talk, self).__init__()    # 继承父类__init__方法
        self.name=name

    def run(self):          # 必须实现一个run方法,规定
        print("%s is say 'Hello'" % self.name)
        time.sleep(random.randint(1,3))
        print("%s talking end"% self.name)

if __name__ == '__main__':
    p1=Talk('Shuke')
    p2=Talk('Eric')
    p3=Talk('Tome')
    p4=Talk('Lucy')

    p1.start()          # start方法会自动调用run方法运行
    p2.start()
    p3.start()
    p4.start()
    print("主线程")

'''
执行结果:
主线程
Shuke is say 'Hello'
Lucy is say 'Hello'
Tome is say 'Hello'
Eric is say 'Hello'
Tome talking end
Eric talking end
Lucy talking end
Shuke talking end
'''

张开进度(形式2)

并发落成socket通讯示例

澳门葡京备用网址 5澳门葡京备用网址 6

from socket import *
from multiprocessing import Process

server = socket(AF_INET, SOCK_STREAM)
server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
server.bind(('127.0.0.1', 8081))
server.listen(5)


def talk(conn, client_addr):
    while True:
        try:
            msg = conn.recv(1024)
            if not msg: break
            conn.send(msg.upper())
        except Exception:
            break


if __name__ == '__main__':  # windows下start进程一定要写到这下面
    while True:
        conn, addr = server.accept()
        p = Process(target=talk, args=(conn, addr))
        p.start()

server端

澳门葡京备用网址 7澳门葡京备用网址 8

from socket import *

client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8081))

while True:
    msg=input('>>:').strip()
    if not msg:continue

    client.send(msg.encode('utf-8'))
    msg=client.recv(1024)
    print(msg.decode('utf-8'))

client端

存在的标题:

每来贰个客户端,都在服务端开启三个进度,假诺并发来2个万个客户端,要展开两万个经过吗,你协和尝试着在您本人的机械上开启三万个,八万个进程试壹试。

减轻方式:进度池

1.6 线程queue

queue队列 :使用import queue,用法与经过Queue一样

import queue



q=queue.Queue(3) #队列:先进先出



q.put(1)

q.put(2)

q.put(3)

# q.put(4)

# q.put_nowait(4)

# q.put(4,block=False)

q.put(4,block=True,timeout=3)





# print(q.get())

# print(q.get())

# print(q.get())



q=queue.LifoQueue(3) #堆栈:后进先出

q.put(1)

q.put(2)

q.put(3)



print(q.get())

print(q.get())

print(q.get())



q=queue.PriorityQueue(3) #优先级队列

q.put((10,'a'))

q.put((-3,'b'))

q.put((100,'c'))



print(q.get())

print(q.get())

print(q.get())

 

 

 

1.5 定时器

沙漏,内定n秒后进行某操作

from threading import Timer





def hello(name):

    print("hello, world %s " %name)





t = Timer(3, hello,args=('egon',))

t.start()  # after 1 seconds, "hello, world" will be printed

 

 

小结:1个cpu同一时半刻刻只可以运营1个“任务”;真正的并行实施多职责只能在多核CPU上贯彻,不过,由于职分数量远远多于CPU的骨干数据,所以,操作系统也会自动把大多义务轮流动调查整到每其中央上施行。

二. Process对象的任何措施和属性

经过对象的其他格局1:terminate,is_alive

澳门葡京备用网址 9澳门葡京备用网址 10

import time
import random
from multiprocessing import Process


class Talk(Process):    # 继承Process类

    def __init__(self,name):
        super(Talk, self).__init__()    # 继承父类__init__方法
        self.name=name

    def run(self):          # 必须实现一个run方法,规定
        print("%s is say 'Hello'" % self.name)
        time.sleep(random.randint(1,3))
        print("%s talking end"% self.name)

if __name__ == '__main__':
    p1=Talk('Shuke')

    p1.start()          # start方法会自动调用run方法运行
    p1.terminate()      # 关闭进程,不会立即关闭,所以is_alive立刻查看的结果可能还是存活
    print(p1.is_alive())# True
    time.sleep(1)       # 模拟CPU调度的延时
    print("====分割线====")
    print(p1.is_alive())# False

'''
执行结果:
True
====分割线====
False
'''

terminate,is_alive

经过对象的任何措施二:p1.daemon=True,p一.join

澳门葡京备用网址 11澳门葡京备用网址 12

import time
import random
from multiprocessing import Process


class Talk(Process):

    def __init__(self,name):
        super(Talk, self).__init__()
        self.name=name

    def run(self):
        print("%s is say 'Hello'" % self.name)
        time.sleep(random.randint(1,3))
        print("%s talking end"% self.name)

if __name__ == '__main__':
    p1=Talk('Shuke')
    p1.daemon = True    # 一定要在p1.start()前设置,设置p1为守护进程,禁止p1创建子进程,并且父进程结束,p1跟着一起结束
    p1.start()          # start方法会自动调用run方法运行
    p1.join(0.0001)     # 等待p1停止,等0.0001秒就不再等了

p1.daemon=True,p1.join

剖析p1.join

澳门葡京备用网址 13澳门葡京备用网址 14

from multiprocessing import Process

import time
import random
def piao(name):
    print('%s is piaoing' %name)
    time.sleep(random.randint(1,3))
    print('%s is piao end' %name)

p1=Process(target=piao,args=('egon',))
p2=Process(target=piao,args=('alex',))
p3=Process(target=piao,args=('yuanhao',))
p4=Process(target=piao,args=('wupeiqi',))

p1.start()
p2.start()
p3.start()
p4.start()

p1.join()
p2.join()
p3.join()
p4.join()

print('主线程')

#疑问:既然join是等待进程结束,那么我像下面这样写,进程不就又变成串行的了吗?
#当然不是了
#注意:进程只要start就会在开始运行了,所以p1-p4.start()时,系统中已经有四个并发的进程了
#而我们p1.join()是在等p1结束,没错p1只要不结束主线程就会一直卡在原地,这也是问题的关键
#join是让主线程等,而p1-p4仍然是并发执行的,p1.join的时候,其余p2,p3,p4仍然在运行,等p1.join结束,可能p2,p3,p4早已经结束了,这样p2.join,p3.join.p4.join直接通过
# 所以4个join花费的总时间仍然是耗费时间最长的那个进程运行的时间


#上述启动进程与join进程可以简写为
p_l=[p1,p2,p3,p4]

for p in p_l:
    p.start()

for p in p_l:
    p.join()

有了join,程序不正是串行了呢???

经过对象的任何品质:name,pid

澳门葡京备用网址 15澳门葡京备用网址 16

import time
import random
from multiprocessing import Process


class Talk(Process):

    def __init__(self,name):
        # self.name=name
        # super().__init__() #Process的__init__方法会执行self.name=Piao-1,
        #                    #所以加到这里,会覆盖我们的self.name=name

        # 为我们开启的进程设置名字的做法
        super().__init__()
        self.name=name

    def run(self):
        print("%s is say 'Hello'" % self.name)
        time.sleep(random.randint(1,3))
        print("%s talking end"% self.name)

if __name__ == '__main__':
    p1=Talk('Shuke')
    p1.start()          # start方法会自动调用run方法运行
    print("====")
    print(p1.pid)       # 查看pid

'''
执行结果:
====
20484
Shuke is say 'Hello'
Shuke talking end
'''

属性:name,pid

一.七 进度池线程池

#付出任务的三种方法:

#共同调用:提交完职分后,就在原地等待,等待任务实行达成,获得职责的再次来到值,才能承接下1行代码,导致程序串行实践

#异步调用+回调机制:提交完职责后,不在原地等候,职责一旦实践达成就会触发回调函数的施行,
程序是出新施行

 

#进度的进行情形:

#阻塞

#非阻塞

 

 

1.6 线程queue

queue队列 :使用import queue,用法与经过Queue一样

import queue



q=queue.Queue(3) #队列:先进先出



q.put(1)

q.put(2)

q.put(3)

# q.put(4)

# q.put_nowait(4)

# q.put(4,block=False)

q.put(4,block=True,timeout=3)





# print(q.get())

# print(q.get())

# print(q.get())



q=queue.LifoQueue(3) #堆栈:后进先出

q.put(1)

q.put(2)

q.put(3)



print(q.get())

print(q.get())

print(q.get())



q=queue.PriorityQueue(3) #优先级队列

q.put((10,'a'))

q.put((-3,'b'))

q.put((100,'c'))



print(q.get())

print(q.get())

print(q.get())

 

 

 

对此操作系统来讲,一个职分正是三个进度(Process),比方展开3个浏览器正是开发银行二个浏览器进程,展开三个记事本就开发银行了2个记事本进度,展开三个记事本就运营了三个记事本进度,张开三个Word就开动了2个Word进程。

3. 进度同步(锁)

进度之间数据不共享,不过共享同一套文件系统,所以访问同三个文本,或同2个打字与印刷终端,是一直不难点的

#多进程共享一个打印终端(用python2测试看两个进程同时往一个终端打印,出现打印到一行的错误)
from multiprocessing import Process
import time
class Logger(Process):
    def __init__(self):
        super(Logger,self).__init__()
    def run(self):
        print(self.name)


for i in range(1000000):
    l=Logger()
    l.start()

#多进程共享一套文件系统
from multiprocessing import Process
import time,random

def work(f,msg):
    f.write(msg)
    f.flush()


f=open('a.txt','w') #在windows上无法把f当做参数传入,可以传入一个文件名,然后在work内用a+的方式打开文件,进行写入测试
for i in range(5):
    p=Process(target=work,args=(f,str(i)))
    p.start()

注:
既然可以用文件共享数据,那么进度间通讯用文件作为数据传输介质就足以了啊,能够,不过有标题:

1.效率

二.亟需协调加锁管理

需知:加锁的目标是为了保障三个经过修改同1块数据时,同目前间只可以有3个改造,即串行的退换,没有错,速度是慢了,就义了进度而保障了数据安全。

经过之间数据隔开分离,不过共享壹套文件系统,因此可以透过文件来兑现进程一贯的通讯,但难点是必须本人加锁管理。所以,就让大家用文件作为数据库,模拟抢票,(Lock互斥锁),见下文抢票示例。

学习了通过使用共享的文书的主意,完成进程一向的共享,即共享数据的秘籍,那种艺术必须惦念全面同步、锁等主题素材。而且文件是操作系统提供的指雁为羹,能够看做进程平昔通讯的介质,与mutiprocess模块毫不相关。

但实在mutiprocessing模块为大家提供了依据音讯的IPC通讯机制:队列和管道。

IPC机制中的队列又是基于(管道+锁)达成的,能够让大家从繁杂的锁难题中脱身出来,我们应有尽量防止使用共享数据,尽只怕使用新闻传递和队列,制止管理千丝万缕的一齐和锁问题,而且在进程数目扩张时,往往可以拿走更加好的可扩张性。

 

一.7.一 同步调用示例:

# from multiprocessing import Pool

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor

import time,random,os



def task(n):

    print('%s is ruuning' %os.getpid())

    time.sleep(random.randint(1,3))

    return n**2



def handle(res):

    print('handle res %s' %res)



if __name__ == '__main__':

    #同步调用

    pool=ProcessPoolExecutor(2)



    for i in range(5):

        res=pool.submit(task,i).result()

        # print(res)

        handle(res)



    pool.shutdown(wait=True)

    # pool.submit(task,33333)

    print('主')

 

 

一.七 进程池线程池

#付给职分的二种格局:

#协助进行调用:提交完职分后,就在原地等候,等待职务实施实现,获得任务的重临值,手艺再三再四下一行代码,导致程序串行实施

#异步调用+回调机制:提交完职分后,不在原地等待,职分壹旦实践达成就会触发回调函数的实行,
程序是出新实施

 

#进度的实市场价格况:

#阻塞

#非阻塞

 

 

有点进度还连连同时干1件事,比方Word,它能够而且张开打字、拼写检查、打印等工作。在二个进程之中,要同时干多件事,就需求同时运行三个“子职责”,大家把经过内的那些“子义务”称为线程(Thread)。

壹.4 进度间通信(IPC)格局一:队列

 进度互相之间相互隔开分离,要完结进度间通讯,即IPC,multiprocessing模块扶助二种样式:队列和管道,这三种方法都以行使新闻传递的,普及应用在分布式系统中。

Queue模块有两种队列及构造函数:
  一. Python Queue模块的FIFO队列先进先出。 class Queue.Queue(maxsize)
  二. LIFO类似于堆,即先进后出。 class Queue.LifoQueue(maxsize)
  叁. 还有1种是先期级队列等第越低越先出来。 class
Queue.PriorityQueue(maxsize)

一.七.二 异步调用示例:

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor

import time,random,os



def task(n):

    print('%s is ruuning' %os.getpid())

    time.sleep(random.randint(1,3))

    # res=n**2

    # handle(res)

    return n**2



def handle(res):

    res=res.result()

    print('handle res %s' %res)



if __name__ == '__main__':

    #异步调用

    pool=ProcessPoolExecutor(2)



    for i in range(5):

        obj=pool.submit(task,i)

        obj.add_done_callback(handle) #handle(obj)



    pool.shutdown(wait=True)

    print('主')

 

 

 

一.七.1 同步调用示例:

# from multiprocessing import Pool

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor

import time,random,os



def task(n):

    print('%s is ruuning' %os.getpid())

    time.sleep(random.randint(1,3))

    return n**2



def handle(res):

    print('handle res %s' %res)



if __name__ == '__main__':

    #同步调用

    pool=ProcessPoolExecutor(2)



    for i in range(5):

        res=pool.submit(task,i).result()

        # print(res)

        handle(res)



    pool.shutdown(wait=True)

    # pool.submit(task,33333)

    print('主')

 

 

鉴于每一种进程至少要干壹件事,所以,三个进度至少有一个线程。当然,像Word那种复杂的长河能够有八个线程,多少个线程能够而且进行,二十四线程的实行措施和多进度是同1的,也是由操作系统在四个线程之间火速切换,让各样线程都指日可待地更迭运维,看起来就如同时施行同一。当然,真正地同时实行十二线程须要多核CPU才大概实现。

Queue类(创建队列)

Queue([maxsize]):创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递,底层是以管道和锁的方式实现的。

参数介绍:

maxsize是队列中允许最大项数,省略则无大小限制。    

办法介绍:

主要方式:

q.put方法用以插入数据到队列中,put方法还有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,该方法会阻塞timeout指定的时间,直到该队列有剩余的空间。如果超时,会抛出Queue.Full异常。如果blocked为False,但该Queue已满,会立即抛出Queue.Full异常。
q.get方法可以从队列读取并且删除一个元素。同样,get方法有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,那么在等待时间内没有取到任何元素,会抛出Queue.Empty异常。如果blocked为False,有两种情况存在,如果Queue有一个值可用,则立即返回该值,否则,如果队列为空,则立即抛出Queue.Empty异常.

q.get_nowait():同q.get(False)
q.put_nowait():同q.put(False)

q.empty():调用此方法时q为空则返回True,该结果不可靠,比如在返回True的过程中,如果队列中又加入了项目。
q.full():调用此方法时q已满则返回True,该结果不可靠,比如在返回True的过程中,如果队列中的项目被取走。
q.qsize():返回队列中目前项目的正确数量,结果也不可靠,理由同q.empty()和q.full()一样
q.task_done() 在完成一项工作之后,q.task_done() 函数向任务已经完成的队列发送一个信号
q.join() 实际上意味着等到队列为空,再执行别的操作

其余艺术:

q.cancel_join_thread():不会在进程退出时自动连接后台线程。可以防止join_thread()方法阻塞
q.close():关闭队列,防止队列中加入更多数据。调用此方法,后台线程将继续写入那些已经入队列但尚未写入的数据,但将在此方法完成时马上关闭。如果q被垃圾收集,将调用此方法。关闭队列不会在队列使用者中产生任何类型的数据结束信号或异常。例如,如果某个使用者正在被阻塞在get()操作上,关闭生产者中的队列不会导致get()方法返回错误。
q.join_thread():连接队列的后台线程。此方法用于在调用q.close()方法之后,等待所有队列项被消耗。默认情况下,此方法由不是q的原始创建者的所有进程调用。调用q.cancel_join_thread方法可以禁止这种行为

应用:

'''
multiprocessing 模块支持进程间通信的两种主要形式:管道和队列
都是基于消息传递实现的,都是队列接口
'''

from multiprocessing import Process,Queue
import time

q=Queue(5)
q.put([1,2,3])
q.put(('a','b','c'))
q.put(100)
q.put("Hello World")
q.put({'name':'shuke'})
# q.put('队列满了')           # 如果队列元素满了,后续put进入队列的数据将会处于等待状态,直到队列的元素被消费,才可以加入
print(q.qsize())            # 5; 返回队列的大小
print(q.full())             # True

print(q.get())              # [1, 2, 3]
print(q.get())              # ('a', 'b', 'c')
print(q.get())              # 100
print(q.get())              # Hello World
print(q.get())              # {'name': 'shuke'}
# print(q.get())            # 如果队列元素全部被消费完成,会一直卡住,直到队列中被放入新的元素
print(q.empty())            # True

1.7.3 线程池

from concurrent.futures import ThreadPoolExecutor

from threading import current_thread

import requests

import time



def get(url):

    print('%s GET %s' %(current_thread().getName(),url))

    response=requests.get(url)

    time.sleep(2)

    if response.status_code == 200:

        return {'url':url,'content':response.text}



def parse(res):

    res=res.result()

    print('parse:[%s] res:[%s]' %(res['url'],len(res['content'])))





if __name__ == '__main__':

    pool=ThreadPoolExecutor(2)



    urls=[

        'https://www.baidu.com',

        'https://www.python.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

    ]

    for url in urls:

        pool.submit(get,url).add_done_callback(parse)



    pool.shutdown(wait=True)

 

 

一.7.二 异步调用示例:

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor

import time,random,os



def task(n):

    print('%s is ruuning' %os.getpid())

    time.sleep(random.randint(1,3))

    # res=n**2

    # handle(res)

    return n**2



def handle(res):

    res=res.result()

    print('handle res %s' %res)



if __name__ == '__main__':

    #异步调用

    pool=ProcessPoolExecutor(2)



    for i in range(5):

        obj=pool.submit(task,i)

        obj.add_done_callback(handle) #handle(obj)



    pool.shutdown(wait=True)

    print('主')

 

 

 

小结:

生产者消费者模型

在出现编制程序中运用生产者和顾客格局能够解决一大半油然则生难题。该形式通过平衡生产线程和消费线程的工作技艺来增加程序的完好管理多少的进度。

为啥要选拔生产者和顾客形式

在线程世界里,生产者正是生育数据的线程,消费者就是消费数量的线程。在二十三十二线程开荒个中,假使劳动者管理速度相当的慢,而消费者管理速度极慢,那么生产者就非得等待买主管理完,本领承继生产数量。同样的道理,即便消费者的管理工科夫跨越生产者,那么消费者就务须待产者。为了缓慢解决那些难题于是引进了劳动者和顾客格局。

如何是劳动者消费者形式

生产者消费者形式是透过3个器皿来消除劳动者和消费者的强耦合难点。生产者和顾客相互之间不间接通信,而经过阻塞队列来进展电视发表,所以生产者生产完数据未来并非等待买主管理,直接扔给卡住队列,消费者不找生产者要多少,而是平昔从绿灯队列里取,阻塞队列就相当于三个缓冲区,平衡了劳动者和买主的管理才能。

听他们讲队列达成生产者消费者模型

澳门葡京备用网址 17澳门葡京备用网址 18

from multiprocessing import Process,Queue
import time
import random

def producer(seq,q,name):
    for item in seq:
        time.sleep(random.randint(1,3))
        q.put(item)
        print("%s 生产者生产了: %s"%(name,item))


def consumer(q,name):
    while True:
        time.sleep(random.randint(1,3))
        res=q.get()
        print("%s 消费者消费了: %s"%(name,res))


if __name__ == '__main__':
    q=Queue()
    seq=("苹果%s"% i for i in range(5))

    p=Process(target=consumer,args=(q,'Tom'))       # 以元组的方式传参
    p.start()
    producer(seq,q,'shuke')
    print("=====主线程=====")

'''
执行结果:
shuke 生产者生产了: 苹果0
Tom 消费者消费了: 苹果0
shuke 生产者生产了: 苹果1
Tom 消费者消费了: 苹果1
shuke 生产者生产了: 苹果2
shuke 生产者生产了: 苹果3
Tom 消费者消费了: 苹果2
shuke 生产者生产了: 苹果4
=====主线程=====
Tom 消费者消费了: 苹果3
Tom 消费者消费了: 苹果4
'''

劳动者消费者模型示例(基于队列)

澳门葡京备用网址 19澳门葡京备用网址 20

# 生产者发送结束标志给消费者
from multiprocessing import Process,Queue
import time
import random

def producer(seq,q,name):
    for item in seq:
        time.sleep(random.randint(1,3))
        q.put(item)
        print("%s 生产者生产了: %s"%(name,item))


def consumer(q,name):
    while True:
        time.sleep(random.randint(1,3))
        res=q.get()
        if res is None:break
        print("%s 消费者消费了: %s"%(name,res))


if __name__ == '__main__':
    q=Queue()
    seq=("苹果%s"% i for i in range(5))

    c=Process(target=consumer,args=(q,'Tom'))       # 以元组的方式传参
    c.start()

    producer(seq,q,'shuke')
    q.put(None)
    c.join()    # 主线程等待直到c消费者进程运行结束再继续往下运行
    print("=====主线程=====")

'''
执行结果:
shuke 生产者生产了: 苹果0
Tom 消费者消费了: 苹果0
shuke 生产者生产了: 苹果1
Tom 消费者消费了: 苹果1
shuke 生产者生产了: 苹果2
Tom 消费者消费了: 苹果2
shuke 生产者生产了: 苹果3
Tom 消费者消费了: 苹果3
shuke 生产者生产了: 苹果4
Tom 消费者消费了: 苹果4
=====主线程=====
'''

主线程等到买主停止

1.8 协程

仅仅地切换反而会下跌运作功能

协程:是单线程下的产出,又称微线程,纤程。英文名Coroutine。一句话表达如何是线程:协程是一种用户态的轻量级线程,即协程是由用户程序本身调节调整的。

小结协程特点:

总得在唯有一个单线程里达成产出

修改共享数据不需加锁

用户程序里团结保留多个调整流的内外文栈

叠加:三个体协会程境遇IO操作自动切换成别的协程(怎么样达成检查实验IO,yield、greenlet都心有余而力不足兑现,就用到了gevent模块(select机制))

1.7.3 线程池

from concurrent.futures import ThreadPoolExecutor

from threading import current_thread

import requests

import time



def get(url):

    print('%s GET %s' %(current_thread().getName(),url))

    response=requests.get(url)

    time.sleep(2)

    if response.status_code == 200:

        return {'url':url,'content':response.text}



def parse(res):

    res=res.result()

    print('parse:[%s] res:[%s]' %(res['url'],len(res['content'])))





if __name__ == '__main__':

    pool=ThreadPoolExecutor(2)



    urls=[

        'https://www.baidu.com',

        'https://www.python.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

        'https://www.openstack.org',

    ]

    for url in urls:

        pool.submit(get,url).add_done_callback(parse)



    pool.shutdown(wait=True)

 

 

  • 经过正是一个先后在一个数额集上的三次动态实施进度。进度一般由程序、数据集、进度序调控制块三局地组成。
  • 线程也叫轻量级进度,它是三个为主的CPU奉行单元,也是程序试行进度中的最小单元,由线程ID、程序计数器、寄存器集合和储藏室共同整合。线程的引进减小了先后出现试行时的费用,提升了操作系统的产出质量。线程未有和谐的系统财富。

JoinableQueue类 (创设队列的别的二个类)

JoinableQueue([maxsize]):那就如多个Queue对象,但队列允许项目标顾客通知劳动者队列已经被成功拍卖,文告进度是利用共享的连续信号和条件变量来促成的。

参数介绍:

maxsize是队列中允许最大项数,省略则无大小限制。

办法介绍:

JoinableQueue的实例p除了与Queue对象同样的点子之外还兼具:

  • q.task_done():
    使用者利用此情势发出实信号,表示q.get()的回来项目曾经被管理。假如调用此办法的次数超越从队列中去除项目的数据,将引发ValueError非凡。
  • q.join():
    生产者调用此办法开始展览围堵,直到队列中具有的项目均被拍卖。阻塞将随处到行列中的每种品种均调用q.task_done()方法甘休。

澳门葡京备用网址 21澳门葡京备用网址 22

from multiprocessing import Process,JoinableQueue
import time
import random

def producer(seq,q,name):
    for item in seq:
        q.put(item)
        print("%s 生产者生产了: %s"%(name,item))
    q.join()            # 生产者调用此方法进行阻塞


def consumer(q,name):
    while True:
        res=q.get()
        if res is None:break
        print("%s 消费者消费了: %s"%(name,res))
        q.task_done()       # 使用者使用此方法发出信号,表示q.get()的返回元素已经被消费处理。

if __name__ == '__main__':
    q=JoinableQueue()
    seq=("苹果%s"% i for i in range(5))

    c=Process(target=consumer,args=(q,'Tom'))       # 以元组的方式传参
    c.daemon=True     # 在start之前进行设置为守护进程,在主线程停止时c也停止,但是不用担心,producer内调用q.join保证了consumer已经处理完队列中的所有元素
    c.start()

    producer(seq,q,'shuke')
    print("=====主线程=====")

'''
执行结果:
shuke 生产者生产了: 苹果0
Tom 消费者消费了: 苹果0
shuke 生产者生产了: 苹果1
Tom 消费者消费了: 苹果1
shuke 生产者生产了: 苹果2
Tom 消费者消费了: 苹果2
shuke 生产者生产了: 苹果3
Tom 消费者消费了: 苹果3
shuke 生产者生产了: 苹果4
Tom 消费者消费了: 苹果4
=====主线程=====
'''

q.join与q.task_done示例

澳门葡京备用网址 23澳门葡京备用网址 24

from multiprocessing import Process,JoinableQueue
import time
import random

def producer(seq,q,name):
    for item in seq:
        time.sleep(random.randint(1,3))
        q.put(item)
        print("%s 生产者生产了: %s"%(name,item))
    q.join()


def consumer(q,name):
    while True:
        time.sleep(random.randint(1, 3))
        res=q.get()
        if res is None:break
        print("%s 消费者消费了: %s"%(name,res))
        q.task_done()

if __name__ == '__main__':
    q=JoinableQueue()
    seq=("苹果%s"% i for i in range(5))

    c1=Process(target=consumer,args=(q,'消费者1'))       # 以元组的方式传参
    c2=Process(target=consumer,args=(q,'消费者2'))
    c3=Process(target=consumer,args=(q,'消费者3'))
    c1.daemon=True     # 在start之前进行设置为守护进程,在主线程停止时c也停止,但是不用担心,producer内调用q.join保证了consumer已经处理完队列中的所有元素
    c2.daemon=True
    c3.daemon=True
    c1.start()
    c2.start()
    c3.start()

    producer(seq,q,'shuke')
    print("=====主线程=====")

'''
执行结果:
shuke 生产者生产了: 苹果0
消费者3 消费者消费了: 苹果0
shuke 生产者生产了: 苹果1
消费者1 消费者消费了: 苹果1
shuke 生产者生产了: 苹果2
消费者2 消费者消费了: 苹果2
shuke 生产者生产了: 苹果3
消费者1 消费者消费了: 苹果3
shuke 生产者生产了: 苹果4
消费者3 消费者消费了: 苹果4
=====主线程=====
'''

二个劳动者+多少个顾客

澳门葡京备用网址 25澳门葡京备用网址 26

from multiprocessing import Process,JoinableQueue
import time
import random

def producer(seq,q,name):
    for item in seq:
        # time.sleep(random.randint(1,3))
        q.put(item)
        print("%s 生产者生产了: %s"%(name,item))
    q.join()


def consumer(q,name):
    while True:
        # time.sleep(random.randint(1, 3))
        res=q.get()
        if res is None:break
        print("%s 消费者消费了: %s"%(name,res))
        q.task_done()

if __name__ == '__main__':
    q=JoinableQueue()
    seq=["苹果%s"% i for i in range(5)]

    c1=Process(target=consumer,args=(q,'消费者1'))       # 以元组的方式传参
    c2=Process(target=consumer,args=(q,'消费者2'))
    c3=Process(target=consumer,args=(q,'消费者3'))
    c1.daemon=True     # 在start之前进行设置为守护进程,在主线程停止时c也停止,但是不用担心,producer内调用q.join保证了consumer已经处理完队列中的所有元素
    c2.daemon=True
    c3.daemon=True
    c1.start()
    c2.start()
    c3.start()

    # producer(seq,q,'shuke')     # 也可以是下面三行的形式,开启一个新的子进程当生产者,不用主线程当生产者
    p=Process(target=producer,args=(seq,q,'shuke'))     # 注意此处参数seq为列表
    p.start()
    p.join()
    print("=====主线程=====")

'''
执行结果:
shuke 生产者生产了: 苹果0
shuke 生产者生产了: 苹果1
消费者3 消费者消费了: 苹果0
shuke 生产者生产了: 苹果2
消费者2 消费者消费了: 苹果1
消费者3 消费者消费了: 苹果2
shuke 生产者生产了: 苹果3
消费者2 消费者消费了: 苹果3
shuke 生产者生产了: 苹果4
消费者3 消费者消费了: 苹果4
=====主线程=====
'''

展开三个子进度当作生产者而不是主线程

 

一.8.1 串行实践

import time

def consumer(res):

    '''任务1:接收数据,处理数据'''

    pass



def producer():

    '''任务2:生产数据'''

    res=[]

    for i in range(10000000):

        res.append(i)

    return res



start=time.time()

#串行执行

res=producer()

consumer(res)

stop=time.time()

print(stop-start)

 

 

 

1.8 协程

可是地切换反而会降低运作成效

协程:是单线程下的出现,又称微线程,纤程。英文名Coroutine。一句话表明如何是线程:协程是壹种用户态的轻量级线程,即协程是由用户程序自身主宰调治的。

小结协程特点:

非得在唯有3个单线程里金玉满堂产出

修改共享数据不需加锁

用户程序里自身保留多个调节流的左右文栈

叠加:一个体协会程境遇IO操作自动切换成其余协程(如何贯彻检验IO,yield、greenlet都不能兑现,就用到了gevent模块(select机制))

2、进度和线程的涉嫌

1.伍 进度间通讯(IPC)形式二:管道(通晓一些)

管道也足以说是队列的此外壹种形式,上面大家就开首介绍基于管道实现进程之间的音讯传递

一.8.二 基于yield并发施行

import time

def consumer():

    '''任务1:接收数据,处理数据'''

    while True:

        print('consumer')

        x=yield

        time.sleep(100)



def producer():

    '''任务2:生产数据'''

    g=consumer()

    next(g)

    for i in range(10000000):

        print('producer')

        g.send(i)



start=time.time()

#基于yield保存状态,实现两个任务直接来回切换,即并发的效果

#PS:如果每个任务中都加上打印,那么明显地看到两个任务的打印是你一次我一次,即并发执行的.

producer()



stop=time.time()

print(stop-start) #

 

①.八.一 串行实施

import time

def consumer(res):

    '''任务1:接收数据,处理数据'''

    pass



def producer():

    '''任务2:生产数据'''

    res=[]

    for i in range(10000000):

        res.append(i)

    return res



start=time.time()

#串行执行

res=producer()

consumer(res)

stop=time.time()

print(stop-start)

 

 

 

进度是Computer中的程序关于某数码集上的1次运维活动,是系统开始展览能源分配和调节的中坚单位,是操作系统结构的基本功。可能说进程是全部一定独立作用的次序关于某些数据集上的一回运营活动,进度是系统开展能源分配和调整的1个单独单位。
线程则是经过的1个实体,是CPU调治和分担的骨干单位,它是比进度越来越小的能独立运营的着力单位。

Pipe类(创造管道)

Pipe([duplex]): 在进程之间创建一条管道,并返回元组(conn1,conn2),其中conn1,conn2表示管道两端的连接对象,强调一点:必须在产生Process对象之前产生管道

参数介绍:

dumplex:默认管道是全双工的,如果将duplex射成False,conn1只能用于接收,conn2只能用于发送。

措施介绍:

第3方式:

  • conn壹.recv():
    接收conn二.send(obj)发送的目的。要是未有音讯可吸收接纳,recv方法会一直不通。假如再而三的此外壹端已经倒闭,那么recv方法会抛出EOFError。
  • conn一.send(obj): 通过连日发送对象。obj是与系列化包容的大肆对象。

别的办法:

conn1.close():关闭连接。如果conn1被垃圾回收,将自动调用此方法。
conn1.fileno():返回连接使用的整数文件描述符。
conn1.poll([timeout]):如果连接上的数据可用,返回True。timeout指定等待的最长时限。如果省略此参数,方法将立即返回结果。如果将timeout射成None,操作将无限期地等待数据到达。
conn1.recv_bytes([maxlength]):接收c.send_bytes()方法发送的一条完整的字节消息。maxlength指定要接收的最大字节数。如果进入的消息,超过了这个最大值,将引发IOError异常,并且在连接上无法进行进一步读取。如果连接的另外一端已经关闭,再也不存在任何数据,将引发EOFError异常。
conn.send_bytes(buffer [, offset [, size]]):通过连接发送字节数据缓冲区,buffer是支持缓冲区接口的任意对象,offset是缓冲区中的字节偏移量,而size是要发送字节数。结果数据以单条消息的形式发出,然后调用c.recv_bytes()函数进行接收    
conn1.recv_bytes_into(buffer [, offset]):接收一条完整的字节消息,并把它保存在buffer对象中,该对象支持可写入的缓冲区接口(即bytearray对象或类似的对象)。offset指定缓冲区中放置消息处的字节位移。返回值是收到的字节数。如果消息长度大于可用的缓冲区空间,将引发BufferTooShort异常。

听他们说管道达成进度间通讯(与队列的章程是近似的,队列正是管道加锁达成的)

from multiprocessing import Process,Pipe
import time

def consumer(p,name):
    left,right = p
    left.close()
    while True:
        try:
            fruit = right.recv()
            print("%s 收到水果: %s" % (name,fruit))
        except EOFError:
            right.close()
            break

def producer(seq,p):
    left,right = p
    right.close()
    for item in seq:
        left.send(item)
    else:
        left.close()

if __name__ == '__main__':
    left,right = Pipe()
    c1=Process(target=consumer,args=((left,right),'Tom'))
    c1.start()

    seq=(i for i in range(5))
    producer(seq,(left,right))
    right.close()
    left.close()

    c1.join()
    print("===主线程===")

'''
执行结果:
Tom 收到水果: 0
Tom 收到水果: 1
Tom 收到水果: 2
Tom 收到水果: 3
Tom 收到水果: 4
===主线程===
'''

 注:
生产者和顾客都并未应用管道的有些端点,就应当将其关闭,如在劳动者中关闭管道的右端,在顾客中关闭管道的左端。若是忘记试行那些步骤,程序只怕再消费者中的recv()操作上挂起。管道是由操作系统进行引用计数的,必须在具备进程中关闭管道后才能生产EOFError极度。因而在劳动者中关闭管道不会有任何功能,除非消费者中也关闭了同样的管道端点。

管道能够用来双向通讯,平常选择在客户端/服务器中央银行使的伸手/响应模型或远程进程调用,就能够选择管道编写与经过并行的程序,如下:

澳门葡京备用网址 27澳门葡京备用网址 28

from multiprocessing import Process,Pipe

import time,os
def adder(p,name):
    server,client=p
    client.close()
    while True:
        try:
            x,y=server.recv()
        except EOFError:
            server.close()
            break
        res=x+y
        server.send(res)
    print('server done')
if __name__ == '__main__':
    server,client=Pipe()

    c1=Process(target=adder,args=((server,client),'c1'))
    c1.start()

    server.close()

    client.send((10,20))
    print(client.recv())
    client.close()

    c1.join()
    print('主进程')

示例

注:
send()和recv()方法运用pickle模块对目的开始展览系列化。

 

1.9 greenlet模块

假诺大家在单个线程内有1柒个职责,要想达成在四个任务之间切换,使用yield生成器的艺术过于劳顿(要求先赚取起头化二遍的生成器,然后再调用send。。。格外艰难),而利用greenlet模块能够万分简单地得以完结那21个义务平素的切换

设置模块

pip3 install greenlet

 

 

from greenlet import greenlet

import time



def eat(name):

    print('%s eat 1' %name)

    time.sleep(1000)

    g2.switch('egon')

    print('%s eat 2' %name)

    g2.switch()





def play(name):

    print('%s play 1' % name)

    g1.switch()  #可以在第一次switch时传入参数,以后都不需要

    print('%s play 2' % name)



g1=greenlet(eat)

g2=greenlet(play)

 

greenlet只是提供了一种比generator越发简便易行的切换格局,当切到1个职务执行时若是遭遇io,那就原地阻塞,依旧是平素不化解碰着IO自动切换成升高功能的主题素材。

单线程里的那213个职务的代码平常会既有总结操作又有梗塞操作,我们一同能够在实施任务一时遇到阻塞,就应用阻塞的时日去实施职责2。。。。如此,技艺升高成效,那就用到了Gevent模块。

一.八.二 基于yield并发实施

import time

def consumer():

    '''任务1:接收数据,处理数据'''

    while True:

        print('consumer')

        x=yield

        time.sleep(100)



def producer():

    '''任务2:生产数据'''

    g=consumer()

    next(g)

    for i in range(10000000):

        print('producer')

        g.send(i)



start=time.time()

#基于yield保存状态,实现两个任务直接来回切换,即并发的效果

#PS:如果每个任务中都加上打印,那么明显地看到两个任务的打印是你一次我一次,即并发执行的.

producer()



stop=time.time()

print(stop-start) #

 

澳门葡京备用网址 29

一.陆 进程间通讯形式三:共享数据

展望未来,基于音讯传递的出现编制程序是早晚,即正是选用线程,推荐做法也是将先后设计为大气独立的线程群集通过新闻队列调换数据。那样天崩地塌地收缩了对应用锁定和其余一齐手段的供给,还能扩充到布满式系统中。

注:
进度间通讯应该尽量防止使用本节所讲的共享数据的形式

进度间数据是独自的,能够正视队列或管道完结通讯,二者都以依据消息传递的,就算进度间数据独立,但足以经过Manager达成数量共享,事实上Manager的成效远不止于此。

澳门葡京备用网址 30澳门葡京备用网址 31

from multiprocessing import Process,Manager
import os

def foo(name,d,l):
    l.append(os.getpid())
    d[name]=os.getpid()
if __name__ == '__main__':
    with Manager() as manager:
        d=manager.dict({'name':'shuke'})
        l=manager.list(['init',])

        p_l=[]
        for i in range(5):
            p=Process(target=foo,args=('p%s' %i,d,l))
            p.start()
            p_l.append(p)

        for p in p_l:
            p.join() #必须有join不然会报错

        print(d)
        print(l)
'''
执行结果:
{'p0': 62792, 'p4': 63472, 'name': 'shuke', 'p1': 60336, 'p3': 62704, 'p2': 63196}
['init', 60336, 62704, 62792, 63196, 63472]
'''

示例

 

1.10 gevent模块

Gevent
是1个第二方库,能够轻易通过gevent实现产出同步或异步编制程序,在gevent中用到的重中之重情势是格林let,
它是以C扩张模块情势接入Python的轻量级协程。
格林let整体运行在主程序操作系统进度的中间,但它们被合营式地调治。

#用法

g1=gevent.spawn(func,1,,2,3,x=4,y=5)创建一个协程对象g1,spawn括号内第一个参数是函数名,如eat,后面可以有多个参数,可以是位置实参或关键字实参,都是传给函数eat的



g2=gevent.spawn(func2)



g1.join() #等待g1结束



g2.join() #等待g2结束



#或者上述两步合作一步:gevent.joinall([g1,g2])



g1.value#拿到func1的返回值

 

 

from gevent import monkey;monkey.patch_all()

import gevent

import time



def eat(name):

    print('%s eat 1' %name)

    # gevent.sleep(3)

    time.sleep(3)

    print('%s eat 2' %name)





def play(name):

    print('%s play 1' % name)

    # gevent.sleep(2)

    time.sleep(3)

    print('%s play 2' % name)



g1=gevent.spawn(eat,'egon')

g2=gevent.spawn(play,'alex')

# gevent.sleep(1)



# g1.join()

# g2.join()

gevent.joinall([g1,g2])

 

练习

通过gevent完结单线程下的socket并发(from gevent import
monkey;monkey.patch_all()一定要放置导入socket模块从前,不然gevent不能辨识socket的封堵)

服务端

from gevent import monkey,spawn;monkey.patch_all()

from threading import current_thread

from socket import *



def comunicate(conn):

    print('子线程:%s' %current_thread().getName())

    while True:

        try:

            data=conn.recv(1024)

            if not data:break

            conn.send(data.upper())

        except ConnectionResetError:

            break

    conn.close()



def server(ip,port):

    print('主线程:%s' %current_thread().getName())

    server = socket(AF_INET, SOCK_STREAM)

    server.bind((ip,port))

    server.listen(5)



    while True:

        conn, addr = server.accept()

        print(addr)

        # comunicate(conn)

        # t=Thread(target=comunicate,args=(conn,))

        # t.start()

        spawn(comunicate,conn)



    server.close()



if __name__ == '__main__':

    g=spawn(server,'127.0.0.1', 8081)

    g.join()

 

 

客户端

二十八线程并发四个客户端

from socket import *

from threading import current_thread,Thread



def client():

    client=socket(AF_INET,SOCK_STREAM)

    client.connect(('127.0.0.1',8081))



    while True:

        client.send(('%s say hello' %current_thread().getName()).encode('utf-8'))

        data=client.recv(1024)

        print(data.decode('utf-8'))



    client.close()



if __name__ == '__main__':

    for i in range(500):

        t=Thread(target=client)

        t.start()

 

 

 

1.9 greenlet模块

设若大家在单个线程内有21个义务,要想完成在两个义务之间切换,使用yield生成器的不二秘籍过于艰苦(供给先获得初始化一次的生成器,然后再调用send。。。非凡麻烦),而采取greenlet模块可以万分轻巧地促成那贰13个任务平素的切换

安装模块

pip3 install greenlet

 

 

from greenlet import greenlet

import time



def eat(name):

    print('%s eat 1' %name)

    time.sleep(1000)

    g2.switch('egon')

    print('%s eat 2' %name)

    g2.switch()





def play(name):

    print('%s play 1' % name)

    g1.switch()  #可以在第一次switch时传入参数,以后都不需要

    print('%s play 2' % name)



g1=greenlet(eat)

g2=greenlet(play)

 

greenlet只是提供了1种比generator特别便利的切换方式,当切到三个职务施行时1旦遇上io,那就原地阻塞,依然是从未缓和境遇IO自动切换到提高功能的主题素材。

单线程里的那十多少个职责的代码平时会既有总结操作又有不通操作,大家全然能够在实施职责一时遇上阻塞,就接纳阻塞的日子去实践职务贰。。。。如此,才干进步功效,那就用到了Gevent模块。

小结:

一.7 进程同步(锁),能量信号量,事件…

依傍抢票(Lock–>互斥锁)

# 文件db的内容为:{"count":1}
# 注意一定要用双引号,不然json无法识别
from multiprocessing import Process,Lock
import json
import time
import random
import os

def work(filename,lock): #买票
    # lock.acquire()
    with lock:      # with语法下面的代码块执行完毕会自动释放锁
        with open(filename,encoding='utf-8') as f:
            dic=json.loads(f.read())
            # print('剩余票数: %s' % dic['count'])
        if dic['count'] > 0:
            dic['count']-=1
            time.sleep(random.randint(1,3)) #模拟网络延迟
            with open(filename,'w',encoding='utf-8') as f:
                f.write(json.dumps(dic))
            print('%s 购票成功' %os.getpid())
        else:
            print('%s 购票失败' %os.getpid())
    # lock.release()

if __name__ == '__main__':
    lock=Lock()
    p_l=[]
    for i in range(5):
        p=Process(target=work,args=('db',lock))
        p_l.append(p)
        p.start()
    for p in p_l:
        p.join()

    print('主线程')

'''
执行结果:
63448 购票成功
13676 购票失败
61668 购票失败
63544 购票失败
17816 购票失败
主线程
'''

澳门葡京备用网址 32澳门葡京备用网址 33

#互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去,如果指定信号量为3,那么来一个人获得一把锁,计数加1,当计数等于3时,后面的人均需要等待。一旦释放,就有人可以获得一把锁

#信号量与进程池的概念很像,但是要区分开,信号量涉及到加锁的概念

from multiprocessing import Process,Semaphore
import time,random

def go_wc(sem,user):
    sem.acquire()
    print('%s 占到一个茅坑' %user)
    time.sleep(random.randint(0,3)) #模拟每个人拉屎速度不一样,0代表有的人蹲下就起来了
    sem.release()

if __name__ == '__main__':
    sem=Semaphore(5)
    p_l=[]
    for i in range(13):
        p=Process(target=go_wc,args=(sem,'user%s' %i,))
        p.start()
        p_l.append(p)

    for i in p_l:
        i.join()
    print('============》')

信号量Semahpore(同线程一样)

澳门葡京备用网址 34澳门葡京备用网址 35

# python线程的事件用于主线程控制其他线程的执行,事件主要提供了三个方法 set、wait、clear。
# 事件处理的机制:全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,那么event.wait 方法时便不再阻塞。
clear:将“Flag”设置为False
set:将“Flag”设置为True

#_*_coding:utf-8_*_
#!/usr/bin/env python

from multiprocessing import Process,Event
import time,random

def car(e,n):
    while True:
        if not e.is_set(): #Flase
            print('\033[31m红灯亮\033[0m,car%s等着' %n)
            e.wait()
            print('\033[32m车%s 看见绿灯亮了\033[0m' %n)
            time.sleep(random.randint(3,6))
            if not e.is_set():
                continue
            print('走你,car', n)
            break

def police_car(e,n):
    while True:
        if not e.is_set():
            print('\033[31m红灯亮\033[0m,car%s等着' % n)
            e.wait(1)
            print('灯的是%s,警车走了,car %s' %(e.is_set(),n))
            break

def traffic_lights(e,inverval):
    while True:
        time.sleep(inverval)
        if e.is_set():
            e.clear() #e.is_set() ---->False
        else:
            e.set()

if __name__ == '__main__':
    e=Event()
    # for i in range(10):
    #     p=Process(target=car,args=(e,i,))
    #     p.start()

    for i in range(5):
        p = Process(target=police_car, args=(e, i,))
        p.start()
    t=Process(target=traffic_lights,args=(e,10))
    t.start()

    print('============》')

伊夫nt(同线程同样)

 

壹.1壹 MySQL数据库相关概念

MySQL是四个关系型数据库管理种类,由瑞典王国MySQL AB 公司支付,近日属于
Oracle 旗下厂商。MySQL 最盛行的关系型数据库管理体系,在 WEB
应用方面MySQL是最棒的 揽胜极光DBMS (Relational Database Management
System,关周详据库处理体系) 应用程式之一。

壹、数据库服务器:计算机

二、数据库管理软件:MySQL

3、数据库/库:文件夹

4、表:文件

伍、记录:1个事物的1密密麻麻规范的风味:egon,male,1捌,oldgirl

陆、数据:事物的特征,sex=’male’

1.10 gevent模块

Gevent
是3个第一方库,能够轻便通过gevent达成产出同步或异步编制程序,在gevent中用到的珍视情势是格林let,
它是以C扩大模块格局接入Python的轻量级协程。
格林let全部运作在主程序操作系统过程的里边,但它们被合作式地调节。

#用法

g1=gevent.spawn(func,1,,2,3,x=4,y=5)创建一个协程对象g1,spawn括号内第一个参数是函数名,如eat,后面可以有多个参数,可以是位置实参或关键字实参,都是传给函数eat的



g2=gevent.spawn(func2)



g1.join() #等待g1结束



g2.join() #等待g2结束



#或者上述两步合作一步:gevent.joinall([g1,g2])



g1.value#拿到func1的返回值

 

 

from gevent import monkey;monkey.patch_all()

import gevent

import time



def eat(name):

    print('%s eat 1' %name)

    # gevent.sleep(3)

    time.sleep(3)

    print('%s eat 2' %name)





def play(name):

    print('%s play 1' % name)

    # gevent.sleep(2)

    time.sleep(3)

    print('%s play 2' % name)



g1=gevent.spawn(eat,'egon')

g2=gevent.spawn(play,'alex')

# gevent.sleep(1)



# g1.join()

# g2.join()

gevent.joinall([g1,g2])

 

练习

因而gevent完结单线程下的socket并发(from gevent import
monkey;monkey.patch_all()一定要放置导入socket模块此前,不然gevent不能甄别socket的堵塞)

服务端

from gevent import monkey,spawn;monkey.patch_all()

from threading import current_thread

from socket import *



def comunicate(conn):

    print('子线程:%s' %current_thread().getName())

    while True:

        try:

            data=conn.recv(1024)

            if not data:break

            conn.send(data.upper())

        except ConnectionResetError:

            break

    conn.close()



def server(ip,port):

    print('主线程:%s' %current_thread().getName())

    server = socket(AF_INET, SOCK_STREAM)

    server.bind((ip,port))

    server.listen(5)



    while True:

        conn, addr = server.accept()

        print(addr)

        # comunicate(conn)

        # t=Thread(target=comunicate,args=(conn,))

        # t.start()

        spawn(comunicate,conn)



    server.close()



if __name__ == '__main__':

    g=spawn(server,'127.0.0.1', 8081)

    g.join()

 

 

客户端

二十四线程并发八个客户端

from socket import *

from threading import current_thread,Thread



def client():

    client=socket(AF_INET,SOCK_STREAM)

    client.connect(('127.0.0.1',8081))



    while True:

        client.send(('%s say hello' %current_thread().getName()).encode('utf-8'))

        data=client.recv(1024)

        print(data.decode('utf-8'))



    client.close()



if __name__ == '__main__':

    for i in range(500):

        t=Thread(target=client)

        t.start()

 

 

 

  • 3个线程只可以属于二个进度,而三个进度能够有多个线程,但起码有1个线程。

  • 财富分配给进程,同壹过程的装有线程共享该进度的装有财富。

  • CPU分给线程,即确实在CPU上运行的是线程。

1.8 进程池 星级: *****

1.11.1 mysql是什么

#mysql正是一个遵照socket编写的C/S架构的软件

#客户端软件

  mysql自带:如mysql命令,mysqldump命令等

  python模块:如pymysql

 

①.11 MySQL数据库相关概念

MySQL是三个关系型数据库管理类别,由瑞典王国MySQL AB 公司支付,目前属于
Oracle 旗下商家。MySQL 最盛行的关系型数据库管理连串,在 WEB
应用方面MySQL是最棒的 福特ExplorerDBMS (Relational Database Management
System,关周到据库管理种类) 应用程式之壹。

一、数据库服务器:电脑

2、数据库管理软件:MySQL

3、数据库/库:文件夹

4、表:文件

伍、记录:四个东西的一多元标准的特色:egon,male,1八,oldgirl

陆、数据:事物的特征,sex=’male’

三、并行(xing)和并发

如何时候使用进程池?

开多进度的目的是为了并发,若是有多核,日常有多少个核就开多少个经过,进程开启过多,作用反而会骤降(开启进度是索要占用系统财富的,而且展开多余核数目标历程也无从产生相互),但很引人注目须求出现施行的职责要远大于核数,那时大家就可以通过拥戴2个进度池来调控进度数目,比如httpd的长河情势,规定最小进程数和最大进程数…
   

当被操作对象数目相当的小时,能够间接使用multiprocessing中的Process动态成生八个经过,二十一个幸亏,但倘假诺不少个,上千个对象,手动的去界定进度数量却又太过繁琐,此时能够宣布进度池的成效。

对于远程进度调用的高端应用程序来说,应该运用进度池,Pool能够提供钦命数量的历程,供用户调用,当有新的呼吁提交到pool中时,要是池还并未有满,那么就会创建叁个新的过程用来实践该请求;但假使池中的进度数一度高达规定最大值,那么该请求就会等待,直到池中有经过截至,就录取进度池中的进度。

注:
在使用Python进行系统管理的时候,尤其是还要操作五个文件目录,可能远程序调控制多台主机,并行操作能够节省大批量的小运。

一.1一.2 数据库管理软件分类

#分两大类:

  关系型:如sqllite,db2,oracle,access,sql
server,MySQL,注意:sql语句通用

  非关系型:mongodb,redis,memcache

#能够总结的明白为:

    关系型数据库要求有表结构

    非关系型数据库是key-value存款和储蓄的,未有表结构

1.11.1 mysql是什么

#mysql正是三个依照socket编写的C/S架构的软件

#客户端软件

  mysql自带:如mysql命令,mysqldump命令等

  python模块:如pymysql

 

并行管理(Parallel
Processing)是Computer种类中能同时施行多少个或更多少个管理的1种计算情势。并行管理可同时专门的学业于一致程序的不相同方面。并行管理的基本点目标是省去大型和复杂难题的化解岁月。

Pool类(创立进度池)

Pool([numprocess  [,initializer [, initargs]]]):创建进程池

参数介绍:

numprocess:要创建的进程数,如果省略,将默认使用cpu_count()的值
initializer:是每个工作进程启动时要执行的可调用对象,默认为None
initargs:是要传给initializer的参数组

主意介绍:

驷不及舌措施:

p.apply(func [, args [, kwargs]]):在一个池工作进程中执行func(*args,**kwargs),然后返回结果。需要强调的是:此操作并不会在所有池工作进程中并执行func函数。如果要通过不同参数并发地执行func函数,必须从不同线程调用p.apply()函数或者使用p.apply_async()
p.apply_async(func [, args [, kwargs]]):在一个池工作进程中执行func(*args,**kwargs),然后返回结果。此方法的结果是AsyncResult类的实例,callback是可调用对象,接收输入参数。当func的结果变为可用时,将理解传递给callback。callback禁止执行任何阻塞操作,否则将接收其他异步操作中的结果。

p.close():关闭进程池,防止进一步操作。如果所有操作持续挂起,它们将在工作进程终止前完成
p.terminate():立即终止所有工作进程,同时不执行任何清理或结束任何挂起工作。如果p被垃圾回收,将自动调用此函数
P.jion():等待所有工作进程退出。此方法只能在close()或teminate()之后调用

其它艺术:

方法apply_async()和map_async()的返回值是AsyncResul的实例obj。实例具有以下方法
obj.get():返回结果,如果有必要则等待结果到达。timeout是可选的。如果在指定时间内还没有到达,将引发一场。如果远程操作中引发了异常,它将在调用此方法时再次被引发。
obj.ready():如果调用完成,返回True
obj.successful():如果调用完成且没有引发异常,返回True,如果在结果就绪之前调用此方法,引发异常
obj.wait([timeout]):等待结果变为可用。

 应用

 
 提交任务,并在主进程中获得结果(在此之前的Process是施行职务,结果放到队列里,今后得以在主进度中一向得到结果)

from multiprocessing import Pool
import time
def work(n):
    print('开工啦...')
    time.sleep(3)
    return n**2

if __name__ == '__main__':
    q=Pool()

    #异步apply_async用法:如果使用异步提交的任务,主进程需要使用jion,等待进程池内任务都处理完,然后可以用get收集结果,否则,主进程结束,进程池可能还没来得及执行,也就跟着一起结束了
    res=q.apply_async(work,args=(2,))
    q.close()
    q.join() #join在close之后调用
    print(res.get())

    #同步apply用法:主进程一直等apply提交的任务结束后才继续执行后续代码
    # res=q.apply(work,args=(2,))
    # print(res)

一.11.三 下载安装

一.1一.二 数据库管理软件分类

#分两大类:

  关系型:如sqllite,db2,oracle,access,sql
server,MySQL,注意:sql语句通用

  非关系型:mongodb,redis,memcache

#能够轻巧的敞亮为:

    关系型数据库须求有表结构

    非关系型数据库是key-value存款和储蓄的,未有表结构

并发管理(concurrency
Processing)指1个时日段中有多少个程序都处在已运维运作到运行达成之间,且那多少个程序都以在同一个管理机(CPU)上运营,但任3个时刻点上只有1个顺序在管理机(CPU)上运营。

应用进度池维护稳固数目标进度

澳门葡京备用网址 36澳门葡京备用网址 37

'''
Pool内的进程数默认是cpu核数,假设为4(查看方法os.cpu_count())
开启6个客户端,会发现2个客户端处于等待状态
在每个进程内查看pid,会发现pid使用为4个,即多个客户端公用4个进程
'''

from socket import *
from multiprocessing import Pool
import os

server = socket(AF_INET, SOCK_STREAM)
server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
server.bind(('127.0.0.1', 8081))
server.listen(5)


def talk(conn, client_addr):
    print("进程PID: %s"%(os.getpid()))
    while True:
        try:
            msg = conn.recv(1024)
            if not msg: break
            conn.send(msg.upper())
        except Exception:
            break


if __name__ == '__main__':  # windows下start进程一定要写到这下面
    p = Pool()      # 默认使用CPU的核数
    while True:
        conn,client_addr=server.accept()
        p.apply_async(talk,args=(conn,client_addr))
        # p.apply(talk,args=(conn,client_addr))   # #同步的话,则同一时间只有一个客户端能访问

server端

澳门葡京备用网址 38澳门葡京备用网址 39

from socket import *

client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8081))

while True:
    msg=input('>>:').strip()
    if not msg:continue

    client.send(msg.encode('utf-8'))
    msg=client.recv(1024)
    print(msg.decode('utf-8'))

client端

澳门葡京备用网址 40澳门葡京备用网址 41

from socket import *

client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8081))

while True:
    msg=input('>>:').strip()
    if not msg:continue

    client.send(msg.encode('utf-8'))
    msg=client.recv(1024)
    print(msg.decode('utf-8'))

client1端

 

1.11.3.1  Linux版本

一、二进制rpm包安装

yum -y install mysql-server mysql

 

 

二、源码安装

1.解压tar包

cd /software

tar -xzvf mysql-5.6.21-linux-glibc2.5-x86_64.tar.gz

mv mysql-5.6.21-linux-glibc2.5-x86_64 mysql-5.6.21

 

 

二.增加用户与组

groupadd mysql

useradd -r -g mysql mysql

chown -R mysql:mysql mysql-5.6.21

 

叁.安装数据库

su mysql

cd mysql-5.6.21/scripts

./mysql_install_db --user=mysql --basedir=/software/mysql-5.6.21 --datadir=/software/mysql-5.6.21/data

 

 

4.布局文件

cd /software/mysql-5.6.21/support-files

cp my-default.cnf /etc/my.cnf

cp mysql.server /etc/init.d/mysql

vim /etc/init.d/mysql   #若mysql的安装目录是/usr/local/mysql,则可省略此步

修改文件中的两个变更值

basedir=/software/mysql-5.6.21

datadir=/software/mysql-5.6.21/data

 

5.配置碰着变量

vim /etc/profile

export MYSQL_HOME="/software/mysql-5.6.21"

export PATH="$PATH:$MYSQL_HOME/bin"

source /etc/profile

 

 

6.增多自运行服务

chkconfig --add mysql

chkconfig mysql on

 

 

7.启动mysql

service mysql start

 

 

八.登入mysql及改密码与安顿远程访问

mysqladmin -u root password 'your_password'     #修改root用户密码

mysql -u root -p     #登录mysql,需要输入密码

mysql>GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'your_password' WITH GRANT OPTION;     #允许root用户远程访问

mysql>FLUSH PRIVILEGES;     #刷新权限

 

 

3、源码安装mariadb

1. 解压

tar zxvf  mariadb-5.5.31-linux-x86_64.tar.gz  

mv mariadb-5.5.31-linux-x86_64 /usr/local/mysql //必需这样,很多脚本或可执行程序都会直接访问这个目录

 

 

2. 权限

groupadd mysql             //增加 mysql 属组

useradd -g mysql mysql     //增加 mysql 用户 并归于mysql 属组

chown mysql:mysql -Rf  /usr/local/mysql    // 设置 mysql 目录的用户及用户组归属。

chmod +x -Rf /usr/local/mysql    //赐予可执行权限

 

 

3. 拷贝配置文件

cp /usr/local/mysql/support-files/my-medium.cnf /etc/my.cnf     //复制默认mysql配置 文件到/etc目录

 

 

4. 初始化

/usr/local/mysql/scripts/mysql_install_db --user=mysql          //初始化数据库

cp  /usr/local/mysql/support-files/mysql.server    /etc/init.d/mysql    //复制mysql服务程序 到系统目录

chkconfig  mysql on     //添加mysql 至系统服务并设置为开机启动

service  mysql  start  //启动mysql

 

 

5. 环境变量配置

vim /etc/profile   //编辑profile,将mysql的可执行路径加入系统PATH

export PATH=/usr/local/mysql/bin:$PATH

source /etc/profile  //使PATH生效。

 

 

6. 账号密码

mysqladmin -u root password 'yourpassword' //设定root账号及密码

mysql -u root -p  //使用root用户登录mysql

use mysql  //切换至mysql数据库。

select user,host,password from user; //查看系统权限

drop user ''@'localhost'; //删除不安全的账户

drop user root@'::1';

drop user root@127.0.0.1;

select user,host,password from user; //再次查看系统权限,确保不安全的账户均被删除。

flush privileges;  //刷新权限

 

 

7. 一些必要的初始配置

1)修改字符集为UTF8

vi /etc/my.cnf

在[client]下面添加 default-character-set = utf8

在[mysqld]下面添加 character_set_server = utf8

 

二)增添错误日志

vi /etc/my.cnf

在[mysqld]下面添加:

log-error = /usr/local/mysql/log/error.log

general-log-file = /usr/local/mysql/log/mysql.log

3) 设置为不区分大小写,linux下默认会区分大小写。

vi /etc/my.cnf

在[mysqld]下面添加:

lower_case_table_name=1 

修改完重启:

service  mysql  restart

 

 

壹.1一.3 下载安装

澳门葡京备用网址 42

回调函数(callback)  星级: *****

1.11.3.2  Window版本

安装

#1、下载:MySQL Community Server 5.7.16

 

#2、解压

假诺想要让MySQL安装在内定目录,那么就将解压后的公文夹移动到钦点目录,如:C:\mysql-5.7.16-winx64

 

#3、加多境遇变量

【右键Computer】–》【属性】–》【高等系统安装】–》【高档】–》【情形变量】–》【在其次个内容框中找到
变量名称叫Path 的一行,双击】 –>
【将MySQL的bin目录路线追加到变值值中,用 ; 分割】

 

#4、初始化

mysqld --initialize-insecure

 

 

#5、启动MySQL服务

mysqld # 启动MySQL服务

 

 

#陆、运转MySQL客户端并一而再MySQL服务

mysql -u root -p # 连接MySQL服务器

 

 

将MySQL服务塑产生windows服务

上一步解决了一些问题,但不够彻底,因为在执行【mysqd】启动MySQL服务器时,当前终端会被hang住,那么做一下设置即可解决此问题:

注意:--install前,必须用mysql启动命令的绝对路径

# 制作MySQL的Windows服务,在终端执行此命令:

"c:\mysql-5.7.16-winx64\bin\mysqld" --install

 

 

# 移除MySQL的Windows服务,在终端执行此命令:

"c:\mysql-5.7.16-winx64\bin\mysqld" --remove

 

注册成服务之后,以后再启动和关闭MySQL服务时,仅需执行如下命令:

# 启动MySQL服务

net start mysql

 

# 关闭MySQL服务

net stop mysql

 

 

1.11.3.1  Linux版本

一、二进制rpm包安装

yum -y install mysql-server mysql

 

 

2、源码安装

1.解压tar包

cd /software

tar -xzvf mysql-5.6.21-linux-glibc2.5-x86_64.tar.gz

mv mysql-5.6.21-linux-glibc2.5-x86_64 mysql-5.6.21

 

 

二.增加用户与组

groupadd mysql

useradd -r -g mysql mysql

chown -R mysql:mysql mysql-5.6.21

 

3.设置数据库

su mysql

cd mysql-5.6.21/scripts

./mysql_install_db --user=mysql --basedir=/software/mysql-5.6.21 --datadir=/software/mysql-5.6.21/data

 

 

肆.布局文件

cd /software/mysql-5.6.21/support-files

cp my-default.cnf /etc/my.cnf

cp mysql.server /etc/init.d/mysql

vim /etc/init.d/mysql   #若mysql的安装目录是/usr/local/mysql,则可省略此步

修改文件中的两个变更值

basedir=/software/mysql-5.6.21

datadir=/software/mysql-5.6.21/data

 

5.安顿情状变量

vim /etc/profile

export MYSQL_HOME="/software/mysql-5.6.21"

export PATH="$PATH:$MYSQL_HOME/bin"

source /etc/profile

 

 

陆.加多自运转服务

chkconfig --add mysql

chkconfig mysql on

 

 

7.启动mysql

service mysql start

 

 

捌.登陆mysql及改密码与安顿远程访问

mysqladmin -u root password 'your_password'     #修改root用户密码

mysql -u root -p     #登录mysql,需要输入密码

mysql>GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'your_password' WITH GRANT OPTION;     #允许root用户远程访问

mysql>FLUSH PRIVILEGES;     #刷新权限

 

 

三、源码安装mariadb

1. 解压

tar zxvf  mariadb-5.5.31-linux-x86_64.tar.gz  

mv mariadb-5.5.31-linux-x86_64 /usr/local/mysql //必需这样,很多脚本或可执行程序都会直接访问这个目录

 

 

2. 权限

groupadd mysql             //增加 mysql 属组

useradd -g mysql mysql     //增加 mysql 用户 并归于mysql 属组

chown mysql:mysql -Rf  /usr/local/mysql    // 设置 mysql 目录的用户及用户组归属。

chmod +x -Rf /usr/local/mysql    //赐予可执行权限

 

 

3. 拷贝配置文件

cp /usr/local/mysql/support-files/my-medium.cnf /etc/my.cnf     //复制默认mysql配置 文件到/etc目录

 

 

4. 初始化

/usr/local/mysql/scripts/mysql_install_db --user=mysql          //初始化数据库

cp  /usr/local/mysql/support-files/mysql.server    /etc/init.d/mysql    //复制mysql服务程序 到系统目录

chkconfig  mysql on     //添加mysql 至系统服务并设置为开机启动

service  mysql  start  //启动mysql

 

 

5. 环境变量配置

vim /etc/profile   //编辑profile,将mysql的可执行路径加入系统PATH

export PATH=/usr/local/mysql/bin:$PATH

source /etc/profile  //使PATH生效。

 

 

6. 账号密码

mysqladmin -u root password 'yourpassword' //设定root账号及密码

mysql -u root -p  //使用root用户登录mysql

use mysql  //切换至mysql数据库。

select user,host,password from user; //查看系统权限

drop user ''@'localhost'; //删除不安全的账户

drop user [email protected]'::1';

drop user [email protected]127.0.0.1;

select user,host,password from user; //再次查看系统权限,确保不安全的账户均被删除。

flush privileges;  //刷新权限

 

 

7. 一些必要的初始配置

1)修改字符集为UTF8

vi /etc/my.cnf

在[client]下面添加 default-character-set = utf8

在[mysqld]下面添加 character_set_server = utf8

 

二)扩充错误日志

vi /etc/my.cnf

在[mysqld]下面添加:

log-error = /usr/local/mysql/log/error.log

general-log-file = /usr/local/mysql/log/mysql.log

3) 设置为不区分大小写,linux下默认会区分大小写。

vi /etc/my.cnf

在[mysqld]下面添加:

lower_case_table_name=1 

修改完重启:

service  mysql  restart

 

 

现身的入眼是您有管理八个职务的才干,不自然要同时。并行的关键是您有同时处理七个任务的力量。所以说,并行是出新的子集。

一. 不需求回调函数的景色

如果在主进度中等待进度池中存有职分都实施达成后,再统1处理结果,则无需回调函数。

from multiprocessing import Pool
import time,random,os

def work(n):
    time.sleep(1)
    return n**2
if __name__ == '__main__':
    p=Pool()

    res_l=[]
    for i in range(10):
        res=p.apply_async(work,args=(i,))
        res_l.append(res)

    p.close()
    p.join() #等待进程池中所有进程执行完毕

    nums=[]
    for res in res_l:
        nums.append(res.get()) #拿到所有结果
    print(nums) #主进程拿到所有的处理结果,可以在主进程中进行统一进行处理

壹.12 重新恢复设置密码

1.11.3.2  Window版本

安装

#1、下载:MySQL Community Server 5.7.16

 

#2、解压

一经想要让MySQL安装在钦点目录,那么就将解压后的文件夹移动到内定目录,如:C:\mysql-5.7.16-winx64

 

#叁、增添意况变量

【右键Computer】–》【属性】–》【高端系统装置】–》【高端】–》【景况变量】–》【在第3个内容框中找到
变量名字为Path 的一行,双击】 –>
【将MySQL的bin目录路线追加到变值值中,用 ; 分割】

 

#4、初始化

mysqld --initialize-insecure

 

 

#5、启动MySQL服务

mysqld # 启动MySQL服务

 

 

#6、运转MySQL客户端并三番五次MySQL服务

mysql -u root -p # 连接MySQL服务器

 

 

将MySQL服务构建成windows服务

上一步解决了一些问题,但不够彻底,因为在执行【mysqd】启动MySQL服务器时,当前终端会被hang住,那么做一下设置即可解决此问题:

注意:--install前,必须用mysql启动命令的绝对路径

# 制作MySQL的Windows服务,在终端执行此命令:

"c:\mysql-5.7.16-winx64\bin\mysqld" --install

 

 

# 移除MySQL的Windows服务,在终端执行此命令:

"c:\mysql-5.7.16-winx64\bin\mysqld" --remove

 

注册成服务之后,以后再启动和关闭MySQL服务时,仅需执行如下命令:

# 启动MySQL服务

net start mysql

 

# 关闭MySQL服务

net stop mysql

 

 

4、同步与异步

二.  回调函数的行使场景

进度池中其它三个职分一旦管理完了,就立时告知主进程:笔者好了额,你能够拍卖自身的结果了。主进程则调用3个函数去管理该结果,该函数即回调函数。

大家能够把耗费时间间(阻塞)的天职放到进度池中,然后内定回调函数(主进度肩负施行),那样主进度在试行回调函数时就节约了I/O的长河,直接得到的是职责的结果。

from multiprocessing import Pool
import time,random,os

def get_page(url):
    print('(进程 %s) 正在下载页面 %s' %(os.getpid(),url))
    time.sleep(random.randint(1,3))
    return url #用url充当下载后的结果

def parse_page(page_content):
    print('<进程 %s> 正在解析页面: %s' %(os.getpid(),page_content))
    time.sleep(1)
    return '{%s 回调函数处理结果:%s}' %(os.getpid(),page_content)


if __name__ == '__main__':
    urls=[
        'http://maoyan.com/board/1',
        'http://maoyan.com/board/2',
        'http://maoyan.com/board/3',
        'http://maoyan.com/board/4',
        'http://maoyan.com/board/5',
        'http://maoyan.com/board/7',

    ]
    # 要创建进程池中的进程数,如果省略,将默认使用cpu_count()的值
    p=Pool()            
    res_l=[]

    #异步的方式提交任务,然后把任务的结果交给callback处理
    #注意:会专门开启一个进程来处理callback指定的任务(单独的一个进程,而且只有一个)
    for url in urls:
        res=p.apply_async(get_page,args=(url,),callback=parse_page)
        res_l.append(res)

    #异步提交完任务后,主进程先关闭p(必须先关闭),然后再用p.join()等待所有任务结束(包括callback)
    p.close()
    p.join()
    print('{主进程 %s}' %os.getpid())

    #收集结果,发现收集的是get_page的结果
    #所以需要注意了:
    #1. 当我们想要在将get_page的结果传给parse_page处理,那么就不需要i.get(),通过指定callback,就可以将i.get()的结果传给callback执行的任务
    #2. 当我们想要在主进程中处理get_page的结果,那就需要使用i.get()获取后,再进一步处理
    for i in res_l: #本例中,下面这两步是多余的
        callback_res=i.get()
        print(callback_res)

'''
打印结果:
(进程 52346) 正在下载页面 http://maoyan.com/board/1
(进程 52347) 正在下载页面 http://maoyan.com/board/2
(进程 52348) 正在下载页面 http://maoyan.com/board/3
(进程 52349) 正在下载页面 http://maoyan.com/board/4
(进程 52348) 正在下载页面 http://maoyan.com/board/5
<进程 52345> 正在解析页面: http://maoyan.com/board/3
(进程 52346) 正在下载页面 http://maoyan.com/board/7
<进程 52345> 正在解析页面: http://maoyan.com/board/1
<进程 52345> 正在解析页面: http://maoyan.com/board/2
<进程 52345> 正在解析页面: http://maoyan.com/board/4
<进程 52345> 正在解析页面: http://maoyan.com/board/5
<进程 52345> 正在解析页面: http://maoyan.com/board/7
{主进程 52345}
http://maoyan.com/board/1
http://maoyan.com/board/2
http://maoyan.com/board/3
http://maoyan.com/board/4
http://maoyan.com/board/5
http://maoyan.com/board/7
'''

澳门葡京备用网址 43澳门葡京备用网址 44

from multiprocessing import Pool
import time,random
import requests
import re

def get_page(url,pattern):
    response=requests.get(url)
    if response.status_code == 200:
        return (response.text,pattern)

def parse_page(info):
    page_content,pattern=info
    res=re.findall(pattern,page_content)
    for item in res:
        dic={
            'index':item[0],
            'title':item[1],
            'actor':item[2].strip()[3:],
            'time':item[3][5:],
            'score':item[4]+item[5]

        }
        print(dic)
if __name__ == '__main__':
    pattern1=re.compile(r'<dd>.*?board-index.*?>(\d+)<.*?title="(.*?)".*?star.*?>(.*?)<.*?releasetime.*?>(.*?)<.*?integer.*?>(.*?)<.*?fraction.*?>(.*?)<',re.S)

    url_dic={
        'http://maoyan.com/board/7':pattern1,
    }

    p=Pool()
    res_l=[]
    for url,pattern in url_dic.items():
        res=p.apply_async(get_page,args=(url,pattern),callback=parse_page)
        res_l.append(res)

    for i in res_l:
        i.get()

    # res=requests.get('http://maoyan.com/board/7')
    # print(re.findall(pattern,res.text))
'''
执行结果:
{'actor': '阿米尔·汗,萨卡诗·泰瓦,法缇玛·萨那·纱卡', 'index': '1', 'score': '9.8', 'title': '摔跤吧!爸爸', 'time': '2017-05-05'}
{'actor': '李微漪,亦风', 'index': '2', 'score': '9.3', 'title': '重返·狼群', 'time': '2017-06-16'}
{'actor': '高强,于月仙,李玉峰', 'index': '3', 'score': '9.2', 'title': '忠爱无言', 'time': '2017-06-09'}
{'actor': '杨培,尼玛扎堆,斯朗卓嘎', 'index': '4', 'score': '9.1', 'title': '冈仁波齐', 'time': '2017-06-20'}
{'actor': '约翰尼·德普,哈维尔·巴登,布兰顿·思怀兹', 'index': '5', 'score': '8.9', 'title': '加勒比海盗5:死无对证', 'time': '2017-05-26'}
{'actor': '戴夫·帕特尔,鲁妮·玛拉,大卫·文翰', 'index': '6', 'score': '8.8', 'title': '雄狮', 'time': '2017-06-22'}
{'actor': '蔡卓妍,周柏豪,钟欣潼', 'index': '7', 'score': '8.6', 'title': '原谅他77次', 'time': '2017-06-23'}
{'actor': '水田山葵,山新,大原惠美', 'index': '8', 'score': '8.6', 'title': '哆啦A梦:大雄的南极冰冰凉大冒险', 'time': '2017-05-30'}
{'actor': '盖尔·加朵,克里斯·派恩,罗宾·怀特', 'index': '9', 'score': '8.6', 'title': '神奇女侠', 'time': '2017-06-02'}
{'actor': '范楚绒,洪海天,谢元真', 'index': '10', 'score': '8.5', 'title': '潜艇总动员之时光宝盒', 'time': '2015-05-29'}
'''

爬虫应用

一.12.1 设置密码

C:\Users\Administrator> mysqladmin -uroot -p password "123"

 

 

壹.1贰 重新恢复设置密码

在管理器世界,同步正是指二个历程在实施有些请求的时候,若该请求须要一段时间才干回来新闻,那么这一个进程将会间接等候下去,直到收到再次回到新闻才继续试行下去。

**apply_async(非阻塞**)和apply(**阻塞**)的界别示例:**

**运用进度池(非阻塞,apply_async**

澳门葡京备用网址 45澳门葡京备用网址 46

from multiprocessing import Process,Pool
import time

def func(msg):
    print( "msg:", msg)
    # time.sleep(1)
    return 'Bye Bye!'

if __name__ == "__main__":
    processes=4                 # 进程池的进程总数
    pool = Pool(processes)      # 实例化
    res_l=[]
    for i in range(5):
        msg = "hello 同学%s" % str(i)
        res=pool.apply_async(func, args=(msg,))   # 维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去
        res_l.append(res)

    print("============= 我是分割线 =================")
    pool.close()        # 关闭进程池,防止进一步操作。如果所有操作持续挂起,它们将在工作进程终止前完成
    pool.join()         # 调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool进程池,join函数等待所有子进程结束
    print("Sub-process(es) done.")
    for i in res_l:
        print(res.get())

'''
执行结果:
============= 我是分割线 =================
msg: hello 同学0
msg: hello 同学1
msg: hello 同学2
msg: hello 同学3
msg: hello 同学4
Sub-process(es) done.
Bye Bye!
Bye Bye!
Bye Bye!
Bye Bye!
Bye Bye!
'''

apply_async

动用进度池(阻塞,apply

澳门葡京备用网址 47澳门葡京备用网址 48

from multiprocessing import Process,Pool
import time

def func(msg):
    print( "msg:", msg)
    # time.sleep(1)
    return 'Bye Bye!'

if __name__ == "__main__":
    processes=4                 # 进程池的进程总数
    pool = Pool(processes)      # 实例化
    res_l=[]
    for i in range(5):
        msg = "hello 同学%s" % str(i)
        res=pool.apply(func, args=(msg,))   # 维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去
        res_l.append(res)                   # 同步执行,即执行完一个拿到结果,再去执行另外一个

    print("============= 我是分割线 =================")
    pool.close()        # 关闭进程池,防止进一步操作。如果所有操作持续挂起,它们将在工作进程终止前完成
    pool.join()         # 调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool进程池,join函数等待所有子进程结束
    print("Sub-process(es) done.")
    print(res_l)
    for i in res_l:     # apply是同步的,所以直接得到结果,没有get()方法
        print(res)

'''
执行结果:
msg: hello 同学0
msg: hello 同学1
msg: hello 同学2
msg: hello 同学3
msg: hello 同学4
============= 我是分割线 =================
Sub-process(es) done.
['Bye Bye!', 'Bye Bye!', 'Bye Bye!', 'Bye Bye!', 'Bye Bye!']
Bye Bye!
Bye Bye!
Bye Bye!
Bye Bye!
Bye Bye!
'''

apply

澳门葡京备用网址 49澳门葡京备用网址 50

#coding: utf-8
import multiprocessing
import os, time, random

def Lee():
    print("\nRun task Lee-%s" %(os.getpid())) #os.getpid()获取当前的进程的ID
    start = time.time()
    time.sleep(random.random() * 10) #random.random()随机生成0-1之间的小数
    end = time.time()
    print('Task Lee, runs %0.2f seconds.' %(end - start))

def Marlon():
    print("\nRun task Marlon-%s" %(os.getpid()))
    start = time.time()
    time.sleep(random.random() * 40)
    end=time.time()
    print('Task Marlon runs %0.2f seconds.' %(end - start))

def Allen():
    print("\nRun task Allen-%s" %(os.getpid()))
    start = time.time()
    time.sleep(random.random() * 30)
    end = time.time()
    print('Task Allen runs %0.2f seconds.' %(end - start))

def Frank():
    print("\nRun task Frank-%s" %(os.getpid()))
    start = time.time()
    time.sleep(random.random() * 20)
    end = time.time()
    print('Task Frank runs %0.2f seconds.' %(end - start))

def Egon():
    print("\nRun task Egon-%s" %(os.getpid()))
    start = time.time()
    time.sleep(random.random() * 20)
    end = time.time()
    print('Task Egon runs %0.2f seconds.' %(end - start))

def Lily():
    print("\nRun task Lily-%s" %(os.getpid()))
    start = time.time()
    time.sleep(random.random() * 20)
    end = time.time()
    print('Task Lily runs %0.2f seconds.' %(end - start))

if __name__=='__main__':
    function_list=  [Lee, Marlon, Allen, Frank, Egon, Lily]
    print("parent process %s" %(os.getpid()))

    pool=multiprocessing.Pool(4)
    for func in function_list:
        pool.apply_async(func)     #Pool执行函数,apply执行函数,当有一个进程执行完毕后,会添加一个新的进程到pool中

    print('Waiting for all subprocesses done...')
    pool.close()
    pool.join()    #调用join之前,一定要先调用close() 函数,否则会出错, close()执行后不会有新的进程加入到pool,join函数等待素有子进程结束
    print('All subprocesses done.')

多个进程池

七个进度池

 

一.1贰.2 重新设置密码

net stop MySQL

mysqld --skip-grant-tables

mysql -uroot -p

    update mysql.user set password=password("") where user='root' and host="localhost";

    flush privileges;



C:\Users\Administrator>tasklist |findstr mysql

mysqld.exe                    6316 Console                    1    454,544 K



C:\Users\Administrator>taskkill /F /PID 6316

成功: 已终止 PID 为 6316 的进程。



C:\Users\Administrator>net start MySQL

MySQL 服务正在启动 .

MySQL 服务已经启动成功。

 

 

一.1二.1 设置密码

C:\Users\Administrator> mysqladmin -uroot -p password "123"

 

 

异步是指进程不须求直接等下去,而是继续试行其余操作,不管其余进程的境况。当有音信重回时系统会公告进度展开管理,那样能够加强实践的作用。例如,打电话时尽管一头通讯,发短息时正是异步通讯。

2. python并发编制程序之十二线程

 

1.壹叁 统一字符编码

#一. 改变配置文件

[mysqld]

default-character-set=utf8

[client]

default-character-set=utf8

[mysql]

default-character-set=utf8



#mysql5.5以上:修改方式有所改动

[mysqld]

character-set-server=utf8

collation-server=utf8_general_ci

[client]

default-character-set=utf8

[mysql]

default-character-set=utf8

 

 

#二. 重启服务

#3. 查看修改结果:

mysql> \s

show variables like '%char%'

 

 

壹.1二.2 重新初始化密码

net stop MySQL

mysqld --skip-grant-tables

mysql -uroot -p

    update mysql.user set password=password("") where user='root' and host="localhost";

    flush privileges;



C:\Users\Administrator>tasklist |findstr mysql

mysqld.exe                    6316 Console                    1    454,544 K



C:\Users\Administrator>taskkill /F /PID 6316

成功: 已终止 PID 为 6316 的进程。



C:\Users\Administrator>net start MySQL

MySQL 服务正在启动 .

MySQL 服务已经启动成功。

 

 

举个例证:

2.1 threading模块

multiprocess模块的接口完全模拟了threading模块的接口,二者在选取范围,有非常大的相似性,由此不再详细介绍。

1.14 初识SQL

有了mysql这几个数据库软件,就足以将程序猿从对数据的治本中脱身出来,专注于对程序逻辑的编排

mysql服务端软件即mysqld帮我们管理好文件夹以及文件,前提是当做使用者的大家,必要下载mysql的客户端,恐怕别的模块来连接受mysqld,然后选择mysql软件规定的语法格式去付出自身命令,达成对文件夹或文件的治本。该语法即sql(Structured
Query Language 即结构化查询语言)

SQL语言主要用以存取数据、查询数据、更新数据和管制关周密据库系统,SQL语言由IBM开采。SQL语言分为叁类别型:

#一、DDL语句    数据库定义语言:
数据库、表、视图、索引、存款和储蓄进程,举例CREATE DROP ALTEKoleos

#2、DML语句    数据库垄断(monopoly)语言:
插入数据INSERT、删除数据DELETE、更新数据UPDATE、查询数据SELECT

#③、DCL语句    数据库调整语言: 比如调控用户的拜访权限GRANT、REVOKE

 

一.一3 统一字符编码

#一. 改造配置文件

[mysqld]

default-character-set=utf8

[client]

default-character-set=utf8

[mysql]

default-character-set=utf8



#mysql5.5以上:修改方式有所改动

[mysqld]

character-set-server=utf8

collation-server=utf8_general_ci

[client]

default-character-set=utf8

[mysql]

default-character-set=utf8

 

 

#二. 重启服务

#三. 翻看修改结果:

mysql> \s

show variables like '%char%'

 

 

是因为CPU和内部存款和储蓄器的进程远远不止外设的速度,所以,在IO编制程序中,就存在速度严重不包容的难题。比如要把100M的数据写入磁盘,CPU输出⑩0M的数量只须要0.0壹秒,不过磁盘要选用这100M数额恐怕供给10秒,有二种方法化解:

二.一.1张开线程的两种办法(同Process)

# 方法一
from threading import Thread
import time


def sayhi(name):
    time.sleep(2)
    print('%s say hello!'% name)

if __name__ == '__main__':
    t = Thread(target=sayhi,args=('shuke',))
    t.start()
    print("=====我是分割线=====")
    print("主线程")

# 方法二
from threading import Thread
import time


class Sayhi(Thread):
    def __init__(self,name):
        super().__init__()
        self.name=name
    def run(self):
        time.sleep(2)
        print("%s say hello!"%self.name)

if __name__ == '__main__':
    t=Sayhi('shuke')
    t.start()
    print("=====我是分割线=====")
    print("主线程")

一.14.一 操作文件夹(库)

1.14 初识SQL

有了mysql这几个数据库软件,就足以将工程师从对数据的管住中脱身出来,专注于对程序逻辑的编纂

mysql服务端软件即mysqld帮我们管理好文件夹以及文件,前提是用作使用者的大家,需求下载mysql的客户端,或然别的模块来连接受mysqld,然后利用mysql软件规定的语法格式去付出本身命令,达成对文本夹或文件的管理。该语法即sql(Structured
Query Language 即结构化查询语言)

SQL语言主要用来存取数据、查询数据、更新数据和保管关周详据库系统,SQL语言由IBM开辟。SQL语言分为三连串型:

#一、DDL语句    数据库定义语言:
数据库、表、视图、索引、存款和储蓄进度,举个例子CREATE DROP ALTE中华V

#贰、DML语句    数据库垄断(monopoly)语言:
插入数据INSERT、删除数据DELETE、更新数据UPDATE、查询数据SELECT

#叁、DCL语句    数据库调控语言: 举个例子调控用户的拜访权限GRANT、REVOKE

 

  1. CPU等着,也正是先后暂停施行后续代码,等100M的多少在10秒后写入磁盘,再跟着往下实行,那种情势称为同步IO
  2. CPU不等待,只是告诉磁盘,渐渐写不心急,写完布告自身,小编随后干别的事去了,于是继续代码能够接着实行,那种格局称为异步IO

二.1.二 子线程与子进度的界别 

1.14.1.1  增

create database db1 charset utf8;

 

一.1四.1 操作文件夹(库)

五、threading模块

线程与经过的试行进程相比较

一. 基于输出结果相比较

澳门葡京备用网址 51澳门葡京备用网址 52

# 线程方式
from threading import Thread

def work():
    print("Hello python!")

if __name__ == '__main__':
    t = Thread(target=work)
    t.start()
    print('主线程/主进程')
'''
执行结果:
Hello python!
主线程/主进程
'''

线程

澳门葡京备用网址 53澳门葡京备用网址 54

# 进程方式
from multiprocessing import Process

def work():
    print("Hello python!")

if __name__ == '__main__':
    t = Process(target=work)
    t.start()
    print('主线程/主进程')
'''
执行结果:
主线程/主进程
Hello python!
'''

进程

注:
相比实施结果,能够看到线程的推行进度>进度的施行进度

二. 依照pid来张开相比较

澳门葡京备用网址 55澳门葡京备用网址 56

# 线程方式
# 在主进程下开启多个线程,每个线程都跟主进程的pid一样
from threading import Thread
import os

def work():
    print("Pid: %s" % os.getpid())

if __name__ == '__main__':
    t1 = Thread(target=work)
    t2 = Thread(target=work)
    t3 = Thread(target=work)
    t1.start()
    t2.start()
    t3.start()
    print("主线程/主进程pid: %s" % os.getpid())
'''
执行结果:
Pid: 65652
Pid: 65652
Pid: 65652
主线程/主进程pid: 65652
'''

线程

澳门葡京备用网址 57澳门葡京备用网址 58

# 进程方式
# 开多个进程,每个进程都有不同的pid
from multiprocessing import Process
import os

def work():
    print("Pid: %s" % os.getpid())

if __name__ == '__main__':
    t1 = Process(target=work)
    t2 = Process(target=work)
    t3 = Process(target=work)
    t1.start()
    t2.start()
    t3.start()
    print('主线程/主进程pid: %s' % os.getpid())
'''
主线程/主进程pid: 20484
Pid: 5800
Pid: 67076
Pid: 62244
'''

进程

1.14.1.2  查

show databases;

show create database db1;

 

1.14.1.1  增

create database db1 charset utf8;

 

线程是操作系统直接帮助的施行单元,因此,高端语言平日都内置二1010二线程的支撑,Python也不例外,并且,Python的线程是真正的Posix
Thread,而不是效仿出来的线程。

2.一.3 小小的演练

演习一: 四线程并发的socket服务端

澳门葡京备用网址 59澳门葡京备用网址 60

#_*_coding:utf-8_*_
#!/usr/bin/env python
import multiprocessing
import threading

import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind(('127.0.0.1',8080))
s.listen(5)

def action(conn):
    while True:
        data=conn.recv(1024)
        print(data)
        conn.send(data.upper())

if __name__ == '__main__':

    while True:
        conn,addr=s.accept()


        p=threading.Thread(target=action,args=(conn,))
        p.start()

多线程并发的socket服务端

服务端

澳门葡京备用网址 61澳门葡京备用网址 62

#_*_coding:utf-8_*_
#!/usr/bin/env python


import socket

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(('127.0.0.1',8080))

while True:
    msg=input('>>: ').strip()
    if not msg:continue

    s.send(msg.encode('utf-8'))
    data=s.recv(1024)
    print(data)

客户端

客户端

演练2:
多少个职分,一个接到用户输入,3个将用户输入的内容格式化成大写,1个将格式化后的结果存入文件

澳门葡京备用网址 63澳门葡京备用网址 64

from threading import Thread
msg_l=[]
format_l=[]
def talk():
    while True:
        msg=input('>>: ').strip()
        if not msg:continue
        msg_l.append(msg)

def format_msg():
    while True:
        if msg_l:
            res=msg_l.pop()
            format_l.append(res.upper())

def save():
    while True:
        if format_l:
            with open('db.txt','a',encoding='utf-8') as f:
                res=format_l.pop()
                f.write('%s\n' %res)

if __name__ == '__main__':
    t1=Thread(target=talk)
    t2=Thread(target=format_msg)
    t3=Thread(target=save)
    t1.start()
    t2.start()
    t3.start()

示例

1.14.1.3  改

alter database db1 charset gbk;

 

1.14.1.2  查

show databases;

show create database db1;

 

Python的标准库提供了八个模块:_threadthreading_thread是起码模块,threading是高端模块,对_thread进展了包装。绝大多数情景下,我们只要求选择threading这几个高端模块。

2.1.4 线程的join与setdaemon

与经过的方法类似,其实是multiprocessing模仿threading的接口

from threading import Thread
import time

def work(name):
    time.sleep(2)
    print("%s say hello" % name)

if __name__ == '__main__':
    t = Thread(target=work,args=('shuke',))
    t.setDaemon(True)
    t.start()
    t.join()
    print("主线程")
    print(t.is_alive())
'''
执行结果:
shuke say hello
主线程
False
'''

1.14.1.4  删

drop database db1;

 

 

1.14.1.3  改

alter database db1 charset gbk;

 

一. 调用Thread类间接创制

2.一.伍 线程的别的艺术补充

Thread实例对象的艺术

  • isAlive(): 重临线程是或不是活动的。
  • getName(): 重临线程名。
  • setName(): 设置线程名。

threading模块提供的一部分办法

  • threading.currentThread(): 再次来到当前的线程变量。
  • threading.enumerate():
    再次来到二个涵盖正在运营的线程的list。正在运行指线程运维后、截至前,不包蕴运转前和休息后的线程。
  • threading.activeCount():
    重返正在周转的线程数量,与len(threading.enumerate())有同样的结果。

    from threading import Thread
    import threading
    import time

    def work():

    time.sleep(2)
    print(threading.current_thread().getName())
    

    # 在主进度下开启线程
    if name == ‘main‘:

    t = Thread(target=work)
    t.start()
    print(threading.current_thread().getName())
    print(threading.current_thread())     # 主线程
    print(threading.enumerate())            # 连同主线程在内有两个运行的线程
    print(threading.active_count())
    print("主线程/主进程")
    

    ”’
    试行结果:
    MainThread
    <_MainThread(MainThread, started 67280)>
    [<_MainThread(MainThread, started 67280)>, ]
    2
    主线程/主进程
    Thread-1
    ”’

一.1四.二 操作文件(表)

1.14.1.4  删

drop database db1;

 

 

起步3个线程正是把三个函数字传送入并创造Thread实例,然后调用start()发端实施:

 2.1.6 线程池

参考小说:  

 

一.1四.二.一  查看当前所在的文件夹:

select database();

 

一.1四.贰 操作文件(表)

澳门葡京备用网址 65澳门葡京备用网址 66

2.2  Python GIL(Global Interpreter Lock)

'''
定义:
In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple 
native threads from executing Python bytecodes at once. This lock is necessary mainly 
because CPython’s memory management is not thread-safe. (However, since the GIL 
exists, other features have grown to depend on the guarantees that it enforces.)
'''
结论: 在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势

 

 这篇小说深透的辨析了GIL对python十贰线程的影响,强烈推荐看浏览:http://www.dabeaz.com/python/UnderstandingGIL.pdf 

 澳门葡京备用网址 67

那里只需清楚: 有了GIL的存在,同暂且刻统一进度中只有3个线程被实施。

需求:

咱俩有四个职务要求管理,处理格局分明是要玩出并发的功能,化解方案能够是:

方案一:开启多个经过

方案2:1个历程下,开启七个线程 

单核境况下,分析结果: 

  假设多少个职分是持筹握算密集型,未有多核来并行总括,方案一徒增了创办进度的费用,方案二胜

  如果五个任务是I/O密集型,方案一创制进度的开支大,且经过的切换速度远比不上线程,方案二胜

多核情形下,分析结果:

  假使多少个职责是测算密集型,多核意味着并行总括,在python中3个进度中1律时刻只有3个线程推行用不上多核,方案一胜

  如果八个职分是I/O密集型,再多的核也消除不了I/O难题,方案贰胜

多进度适用于计算密集型义务,能够张开多进度来充裕利用多核优势,同时出现管理职责。

三十二线程适用于IO密集型职分,线程之间的付出小,切换速度快,处理速度提高,此时,多核的优势不能够被运用。

结论:
未来的微管理器基本上都以多核,python对于计算密集型的职务开二10三十二线程的功效并不可能推动多大质量上的进级,乃至比不上串行(未有大气切换),不过,对于IO密集型的职务功用依然有料定晋级的。

澳门葡京备用网址 68澳门葡京备用网址 69

#计算密集型
from threading import Thread
from multiprocessing import Process
import os
import time
def work():
    res=0
    for i in range(1000000):
        res+=i

if __name__ == '__main__':
    t_l=[]
    start_time=time.time()
    # for i in range(300): #串行
    #     work()

    for i in range(300):
        t=Thread(target=work) #在我的机器上,4核cpu,多线程大概15秒
        # t=Process(target=work) #在我的机器上,4核cpu,多进程大概10秒
        t_l.append(t)
        t.start()

    for i in t_l:
        i.join()

    stop_time=time.time()
    print('run time is %s' %(stop_time-start_time))

    print('主线程')

算算密集型

澳门葡京备用网址 70澳门葡京备用网址 71

#I/O密集型
from threading import Thread
from multiprocessing import Process
import time
import os
def work():
    time.sleep(2) #模拟I/O操作,可以打开一个文件来测试I/O,与sleep是一个效果
    print(os.getpid())

if __name__ == '__main__':
    t_l=[]
    start_time=time.time()
    for i in range(1000):
        t=Thread(target=work) #耗时大概为2秒
        # t=Process(target=work) #耗时大概为25秒,创建进程的开销远高于线程,而且对于I/O密集型,多cpu根本不管用
        t_l.append(t)
        t.start()

    for t in t_l:
        t.join()
    stop_time=time.time()
    print('run time is %s' %(stop_time-start_time))

I/O密集型 

应用:

十二线程用于IO密集型,如socket,爬虫,web
多进程用于计算密集型,如金融分析

 

壹.14.贰.二  切换文件夹:

use db1;

 

1.1四.贰.一  查看当前所在的文本夹:

select database();

 

 1 import time, threading
 2 
 3 # 新线程执行的代码:
 4 def loop():
 5     print('thread %s is running...' % threading.current_thread().name)
 6     n = 0
 7     while n < 5:
 8         n = n + 1
 9         print('thread %s >>> %s' % (threading.current_thread().name, n))
10         time.sleep(1)
11     print('thread %s ended.' % threading.current_thread().name)
12 
13 print('thread %s is running...' % threading.current_thread().name)
14 t = threading.Thread(target=loop, name='LoopThread')
15 t.start()
16 t.join()
17 print('thread %s ended.' % threading.current_thread().name)
18 
19 
20 #运行结果:
21 #thread MainThread is running...
22 # thread LoopThread is running...
23 # thread LoopThread >>> 1
24 # thread LoopThread >>> 2
25 # thread LoopThread >>> 3
26 # thread LoopThread >>> 4
27 # thread LoopThread >>> 5
28 # thread LoopThread ended.
29 # thread MainThread ended.

 2.3 同步锁

行使方法与经过锁一样

import time
import threading

num = 100  #设定一个共享变量
# R=threading.Lock()

def addNum():
    global num #在每个线程中都获取这个全局变量
    #num-=1
    # R.acquire()
    temp=num
    time.sleep(0.1)
    num =temp-1  # 对此公共变量进行-1操作
    # R.release()

thread_list = []

for i in range(100):
    t = threading.Thread(target=addNum)
    t.start()
    thread_list.append(t)

for t in thread_list: #等待所有线程执行完毕
    t.join()

print('Result: ', num)

 锁平日被用来贯彻对共享财富的协同访问。为每五个共享财富创造3个Lock对象,当你供给拜访该财富时,调用acquire方法来赢得锁对象(借使别的线程已经取得了该锁,则当前线程需等待其被保释),待财富访问完后,再调用release方法释放锁,如下所示:

import threading

R=threading.Lock()

R.acquire()
'''
对公共数据的操作
'''
R.release()

1.14.2.3  增

create table t1(id int,name char);

 

一.1四.贰.贰  切换文件夹:

use db1;

 

实例1

GIL VS Lock

Python已经有二个GIL来保管同一时半刻间只好有一个线程来施行了,为啥那边还供给lock? 

达到共同的认知:锁的目标是为着保证共享的数额,同一时半刻间只可以有1个线程来修改共享的多少

得出结论:珍重不一致的数目就应当加分歧的锁。

末尾,难题就很爽朗了,GIL
与Lock是两把锁,珍贵的数码不均等,前者是解释器级其余(当然维护的正是解释器等级的多少,比方垃圾回收的多寡),后者是保险用户自个儿成本的应用程序的数据,很明显GIL不担任那件事,只好用户自定义加锁管理,即Lock。GIL是解释器级其余锁,LOCK是应用程序品级(用户品级)的锁。

详解:

因为Python解释器会自动定时开始展览内部存储器回收,能够领会为python解释器里有叁个独门的线程,每过壹段时间它起wake
up做二次全局轮询看看怎样内部存款和储蓄器数据是足以被清空的,此时友好的程序
里的线程和
py解释器自身的线程是并发运行的,尽管线程删除了2个变量,py解释器的废料回收线程在清空这一个变量的过程中的clearing时刻,也许三个别样线程正好又再度给那个还没来及得清空的内部存款和储蓄器空间赋值了,结果就有希望新赋值的数额被删除了,为了消除类似的主题材料,python解释器轻松残忍的加了锁,即当一个线程运维时,此外人都无法动,那样就消除了上述的主题素材,
 那足以说是Python早期版本的遗留难点。 

 

1.14.2.4  查

show tables;

show create table t1;

desc t1;

 

1.14.2.3  增

create table t1(id int,name char);

 

由于其余进度暗中认可就会运行三个线程,我们把该线程称为主线程,主线程又足以运维新的线程,Python的threading模块有个current_thread()函数,它世代重回当前线程的实例。主线程实例的名字叫MainThread,子线程的名字在开创时钦定,我们用LoopThread命名子线程。名字只是在打字与印刷时用来显示,完全没有其它意思,要是不起名字Python就活动给线程命名字为Thread-1Thread-2……

二.4 死锁与递归锁

死锁:
 是指八个或多个以上的历程或线程在施行进度中,因争夺财富而变成的一种互动等待的景色,若无外力作用,它们都将不或许推进下去。此时称系统处于死锁状态或系统一发布出了死锁,那一个恒久在互相等待的进程称为死锁进度,如下就是死锁。

澳门葡京备用网址 72澳门葡京备用网址 73

from threading import Thread,Lock
import time
mutexA=Lock()
mutexB=Lock()

class MyThread(Thread):
    def run(self):
        self.func1()
        self.func2()
    def func1(self):
        mutexA.acquire()
        print('\033[41m%s 拿到A锁\033[0m' %self.name)

        mutexB.acquire()
        print('\033[42m%s 拿到B锁\033[0m' %self.name)
        mutexB.release()

        mutexA.release()

    def func2(self):
        mutexB.acquire()
        print('\033[43m%s 拿到B锁\033[0m' %self.name)
        time.sleep(2)

        mutexA.acquire()
        print('\033[44m%s 拿到A锁\033[0m' %self.name)
        mutexA.release()

        mutexB.release()

if __name__ == '__main__':
    for i in range(10):
        t=MyThread()
        t.start()

'''
Thread-1 拿到A锁
Thread-1 拿到B锁
Thread-1 拿到B锁
Thread-2 拿到A锁
然后就卡住,死锁了
'''

死锁示例

消除格局,递归锁,在Python中为了帮助在同壹线程中再3请求同壹财富,python提供了可重入锁索罗德Lock。

以此君越Lock内部维护着三个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源能够被一再require。直到三个线程全数的acquire都被release,其余的线程才具博取能源。上边的例证要是选用逍客Lock代替Lock,则不会发生死锁:

mutexA=mutexB=threading.RLock() #一个线程拿到锁,counter加1,该线程内又碰到加锁的情况,则counter继续加1,这期间所有其他线程都只能等待,等待该线程释放所有锁,即counter递减到0为止

 

1.14.2.5  改

alter table t1 add sex char;

alter table t1 drop sex;

alter table t1 modify name char(16);

alter table t1 change name Name char(13);

 

1.14.2.4  查

show tables;

show create table t1;

desc t1;

 

澳门葡京备用网址 74澳门葡京备用网址 75

2.5 信号量Semahpore

Semaphore处理一个放手的计数器,
每当调用acquire()时内置计数器-一;
调用release() 时内置计数器+一;
计数器无法小于0;当计数器为0时,acquire()将封堵线程直到别的线程调用release()。

实例:(同时只有五个线程能够得到semaphore,即能够限制最都林接数为5)

 

import threading
import time

semaphore = threading.Semaphore(5)  # 设置为5,表示同一时刻可以通过5个线程进行操作

def func():
    if semaphore.acquire():
        print (threading.currentThread().getName() + ' get semaphore')
        time.sleep(2)
        semaphore.release()

for i in range(20):
  t1 = threading.Thread(target=func)
  t1.start()

与进度池是一心不相同的定义,进度池Pool(四),最大不得不发出五个进程,而且从始至终同一时半刻刻只有四个经过存在,不会发出新的,而信号量是暴发一批线程/进程,同临时刻能够经过四个线程/进度张开数量操作。

 

1.14.2.6  删

drop table t1;

 

 

1.14.2.5  改

alter table t1 add sex char;

alter table t1 drop sex;

alter table t1 modify name char(16);

alter table t1 change name Name char(13);

 

 1 import threading
 2 import time
 3 
 4 def countNum(n): # 定义某个线程要运行的函数
 5 
 6     print("running on number:%s" %n)
 7 
 8     time.sleep(3)
 9 
10 if __name__ == '__main__':
11 
12     t1 = threading.Thread(target=countNum,args=(23,)) #生成一个线程实例
13     t2 = threading.Thread(target=countNum,args=(34,))
14 
15     t1.start() #启动线程
16     t2.start()
17 
18     print("ending!")
19 
20 
21 #运行结果:程序打印完“ending!”后等待3秒结束
22 #running on number:23
23 #running on number:34
24 #ending!

2.6 事件Event

     
线程的三个重点天性是各种线程都以单身运营且状态不行预测。假若程序中的别的线程要求经过判别某些线程的场地来分明自个儿下一步的操作,那时线程同步难点就
会变得不得了费劲。为了消除那些主题素材,大家必要利用threading库中的伊芙nt对象。
对象涵盖七个可由线程设置的能量信号标记,它同意线程等待某个事件的产生。在
初步意况下,伊夫nt对象中的时限信号标记被设置为假。尽管有线程等待1个伊芙nt对象,
而那个伊夫nt对象的证明为假,那么这么些线程将会被直接不通直至该标识为真。3个线程假若将一个伊芙nt对象的实信号标记设置为真,它将唤起全部等待这几个伊夫nt对象的线程。假使二个线程等待一个已经被安装为实在伊夫nt对象,那么它将忽略这些事件,
继续实施。(能够结合实际生活中的红绿灯举行领悟)

event.isSet():  #返回event的状态值;
event.wait():   #如果 event.isSet()==False将阻塞线程;
event.set():    #设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
event.clear():  #恢复event的状态值为False。

 能够思虑壹种选择场景(仅仅作为验证),举个例子,大家有七个线程从Redis队列中读取数据来拍卖,这一个线程都要尝尝去连接Redis的劳务,一般景观下,假诺Redis连接不成功,在依次线程的代码中,都会去尝尝再一次连接。如若大家想要在运营时确定保证Redis服务平常,才让那三个职业线程去连接Redis服务器,那么大家就能够接纳threading.伊夫nt机制来和睦种种工作线程的总是操作:主线程中会去品尝连接Redis服务,借使平常的话,触发事件,各职业线程会尝试连接Redis服务。

澳门葡京备用网址 76澳门葡京备用网址 77

import threading
import time
import logging

logging.basicConfig(level=logging.DEBUG, format='(%(threadName)-10s) %(message)s',)

def worker(event):
    logging.debug('Waiting for redis ready...')
    event.wait()
    logging.debug('redis ready, and connect to redis server and do some work [%s]', time.ctime())
    time.sleep(1)

def main():
    readis_ready = threading.Event()
    t1 = threading.Thread(target=worker, args=(readis_ready,), name='t1')
    t1.start()

    t2 = threading.Thread(target=worker, args=(readis_ready,), name='t2')
    t2.start()

    logging.debug('first of all, check redis server, make sure it is OK, and then trigger the redis ready event')
    time.sleep(3) # simulate the check progress
    readis_ready.set()

if __name__=="__main__":
    main()

不了解redis可以参考mysql的例子(一样的道理)

redis示例

澳门葡京备用网址 78澳门葡京备用网址 79

from threading import Thread,Event
import threading
import time,random
def conn_mysql():
    print('\033[41m%s 等待连接mysql。。。\033[0m' %threading.current_thread().getName())
    event.wait()
    print('\033[41mMysql初始化成功,%s开始连接。。。\033[0m' %threading.current_thread().getName())


def check_mysql():
    print('\033[43m正在检查mysql。。。\033[0m')
    time.sleep(random.randint(1,3))
    event.set()
    time.sleep(random.randint(1,3))

if __name__ == '__main__':
    event=Event()
    t1=Thread(target=conn_mysql) #等待连接mysql
    t2=Thread(target=conn_mysql) #等待连接myqsl
    t3=Thread(target=check_mysql) #检查mysql

    t1.start()
    t2.start()
    t3.start()
'''
执行结果:
Thread-1 等待连接mysql。。。
Thread-2 等待连接mysql。。。
正在检查mysql。。。
Mysql初始化成功,Thread-1开始连接。。。
Mysql初始化成功,Thread-2开始连接。。。
'''

mysql示例

threading.伊夫nt的wait方法还收受一个超时参数,暗中认可情形下倘诺事件一样未有发生,wait方法会一向不通下去,而投入这几个超时参数之后,要是打断时间超越那么些参数设定的值之后,wait方法会再次回到。对应于上边包车型大巴运用场景,如若Redis服务器1致没有运转,大家希望子线程能够打字与印刷一些日志来不断地提醒大家脚下从未二个能够接连的Redis服务,大家就足以经过安装这么些超时参数来达到那样的目标:

def conn_mysql():
    count=0
    while not e.is_set():
        print('%s 第 <%s> 次尝试' %(threading.current_thread().getName(),count))
        count+=1
        e.wait(0.5)
    print('%s ready to conn mysql' %threading.current_thread().getName())
    time.sleep(1)

澳门葡京备用网址 80澳门葡京备用网址 81

from threading import Thread,Event
import threading
import time,random
def conn_mysql():
    while not event.is_set():
        print('\033[42m%s 等待连接mysql。。。\033[0m' %threading.current_thread().getName())
        event.wait(0.1)
    print('\033[42mMysql初始化成功,%s开始连接。。。\033[0m' %threading.current_thread().getName())

def check_mysql():
    print('\033[41m正在检查mysql。。。\033[0m')
    time.sleep(random.randint(1,3))
    event.set()
    time.sleep(random.randint(1,3))

if __name__ == '__main__':
    event=Event()
    t1=Thread(target=conn_mysql)
    t2=Thread(target=conn_mysql)
    t3=Thread(target=check_mysql)

    t1.start()
    t2.start()
    t3.start()

修订上述mysql版本

完善mysql示例

诸如此类,大家就足以在伺机Redis服务运行的还要,看到工作线程大将军在等候的场馆。

应用: 连接池

 

一.1四.三 操作文件的剧情(记录)

1.14.2.6  删

drop table t1;

 

 

实例2

2.7 条件Condition(了解)

使得线程等待,唯有知足某条件时,才获释n个线程

import threading

def run(n):
    con.acquire()
    con.wait()
    print("run the thread: %s" %n)
    con.release()

if __name__ == '__main__':

    con = threading.Condition()
    for i in range(10):
        t = threading.Thread(target=run, args=(i,))
        t.start()

    while True:
        inp = input('>>>')
        if inp == 'q':
            break
        con.acquire()
        con.notify(int(inp))
        con.release()

澳门葡京备用网址 82澳门葡京备用网址 83

def condition_func():

    ret = False
    inp = input('>>>')
    if inp == '1':
        ret = True

    return ret


def run(n):
    con.acquire()
    con.wait_for(condition_func)
    print("run the thread: %s" %n)
    con.release()

if __name__ == '__main__':

    con = threading.Condition()
    for i in range(10):
        t = threading.Thread(target=run, args=(i,))
        t.start()

示例

 

1.14.3.1  增

insert into db1.t1 values

 (1,'egon'),

 (2,'alex'),

 (3,'wxx');

 

壹.1④.3 操作文件的剧情(记录)

该实例中国共产党有三个线程:主线程,t一和t二子线程

2.8 定时器Timer

机械漏刻,钦命n秒后举行某操作

from threading import Timer

def hello():
    print("hello, world")

t = Timer(1, hello)
t.start()  # after 1 seconds, "hello, world" will be printed

 

1.14.3.2  查

select id,name from db1.t1;

select * from db1.t1;

 

1.14.3.1  增

insert into db1.t1 values

 (1,'egon'),

 (2,'alex'),

 (3,'wxx');

 

澳门葡京备用网址 84

2.9 线程queue

queue队列 :使用import queue,用法与经过Queue同样

queue is especially useful in threaded programming when information must
be exchanged safely between multiple threads.

1. class queue.``Queue(maxsize=0)
#先进先出

import queue

q=queue.Queue()
q.put('first')
q.put('second')
q.put('third')

print(q.get())
print(q.get())
print(q.get())
'''
结果(先进先出):
first
second
third
'''

2. class queue.``LifoQueue(maxsize=0) #last in fisrt
out 

import queue

q=queue.LifoQueue()
q.put('first')
q.put('second')
q.put('third')

print(q.get())
print(q.get())
print(q.get())
'''
结果(后进先出):
third
second
first
'''

3. class queue.``PriorityQueue(maxsize=0)
#存款和储蓄数据时可安装优先级的队列

import queue

q=queue.PriorityQueue()
#put进入一个元组,元组的第一个元素是优先级(通常是数字,也可以是非数字之间的比较),数字越小优先级越高
q.put((20,'a'))
q.put((10,'b'))
q.put((30,'c'))

print(q.get())
print(q.get())
print(q.get())
'''
结果(数字越小优先级越高,优先级高的优先出队):
(10, 'b')
(20, 'a')
(30, 'c')
'''

 

1.14.3.3  改

update t1 set name='SB' where id=2;

 

1.14.3.2  查

select id,name from db1.t1;

select * from db1.t1;

 

 

二.十 Python规范模块–concurrent.futures

concurrent.futures模块是在Python三.第22中学拉长的。根据Python的合法文书档案,concurrent.futures模块提必要开采者3个实行异步调用的高级接口。concurrent.futures基本上正是在Python的threading和multiprocessing模块之上营造的抽象层,更便于使用。即使那么些抽象层简化了那几个模块的运用,可是也下滑了众多世故,所以一旦你需求管理局地定制化的天职,concurrent.futures或者并不适合你。

concurrent.futures包罗抽象类Executor,它并无法一直被选用,所以你需求动用它的八个子类:ThreadPoolExecutor或然ProcessPoolExecutor。正如您所猜的,这八个子类分别对应着Python的threading和multiprocessing接口。那多个子类都提供了池,你可以将线程也许经过放入在那之中。

 

1.14.3.4  删

delete from t1 where id=2;

 

 

1.14.3.3  改

update t1 set name='SB' where id=2;

 

贰. 自定义Thread类继承式创造

三. 协程

协程:是单线程下的出现,又称微线程,纤程。英文名Coroutine。一句话表达怎么样是线程:协程是一种用户态的轻量级线程,即协程是由用户程序自身决定调节的。

亟待重申的是:

  1. python的线程属于基本等级的,即由操作系统调控调治(如单线程1旦相遇io就被迫交出cpu执行权限,切换别的线程运行)
  2. 单线程内张开协程,一旦遭逢io,从应用程序品级(而非操作系统)调控切换

相比较操作系统调整线程的切换,用户在单线程内决定协程的切换,优点如下:

  1. 协程的切换开支越来越小,属于程序等第的切换,操作系统完全感知不到,因此尤其轻量级
  2. 单线程内就足以兑现产出的效益,最大限度地运用cpu

要贯彻协程,关键在于用户程序本身主宰程序切换,切换在此之前务必由用户程序本中国人民保险公司留协程上三次调用时的状态,如此,每一回重复调用时,能够从上次的地方继续实行

(详细的:协程具备本身的寄存器上下文和栈。协程调整切换时,将寄存器上下文和栈保存到别的地点,在切回到的时候,恢复生机原先保存的寄存器上下文和栈)

为此,大家事先已经学习过壹种在单线程下能够保留程序运营状态的点子,即yield,大家来大致复习一下:

  1. yiled能够保留景况,yield的景况保存与操作系统的保存线程状态很像,可是yield是代码等级决定的,更轻量级
  2. send能够把三个函数的结果传给此外一个函数,以此落成单线程内程序之间的切换 

澳门葡京备用网址 85澳门葡京备用网址 86

#不用yield:每次函数调用,都需要重复开辟内存空间,即重复创建名称空间,因而开销很大
import time
def consumer(item):
    # print('拿到包子%s' %item)
    x=11111111111
    x1=12111111111
    x3=13111111111
    x4=14111111111
    y=22222222222
    z=33333333333
    pass

def producer(target,seq):
    for item in seq:
        target(item)    # 每次调用函数,会临时产生名称空间,调用结束则释放,循环100000000次,则重复这么多次的创建和释放,开销非常大

start_time=time.time()
producer(consumer,range(100000000))
stop_time=time.time()
print('run time is:%s' %(stop_time-start_time))     # 13.474999904632568


#使用yield:无需重复开辟内存空间,即重复创建名称空间,因而开销小
import time
def init(func):
    def wrapper(*args,**kwargs):
        g=func(*args,**kwargs)
        next(g)
        return g
    return wrapper

@init
def consumer():
    x=11111111111
    x1=12111111111
    x3=13111111111
    x4=14111111111
    y=22222222222
    z=33333333333
    while True:
        item=yield
        # print('拿到包子%s' %item)
        pass
def producer(target,seq):
    for item in seq:
        target.send(item) #无需重新创建名称空间,从上一次暂停的位置继续,相比上例,开销小

start_time=time.time()
producer(consumer(),range(100000000))
stop_time=time.time()
print('run time is:%s' %(stop_time-start_time))     # 10.674000024795532

演示表达

协程的概念(满足一,二,3就可称为协程):

  1. 总得在唯有三个单线程里完毕产出
  2. 修改共享数据不需加锁
  3. 用户程序里自个儿童卫生保健留多少个调节流的上下文栈
  4. 外加:1个体协会程遭逢IO操作自动切换成别的协程(怎么着促成检查实验IO,yield、greenlet都不可能落成,就用到了gevent模块(select机制)

缺点:

协程的昆仑山真面目是单线程下,不能运用多核,能够是三个主次开启多少个进程,种种进程内张开三个线程,种种线程内张开协程。

协程指的是单个线程,因此1旦协程出现堵塞,将会堵塞整个线程。

 

壹.1五 存款和储蓄引擎

储引擎即表类型,mysql依据不一致的表类型会有例外的拍卖体制

翻开引擎

show engines;

 

创设引擎

create table t1(id int)engine=innodb;

create table t2(id int)engine=myisam;

create table t3(id int)engine=memory;

create table t4(id int)engine=blackhole;

澳门葡京备用网址, 

 

1.14.3.4  删

delete from t1 where id=2;

 

 

澳门葡京备用网址 87澳门葡京备用网址 88

4. 协程模块greenlet

 greenlet是二个用C完结的协程模块,比较与python自带的yield,它可以使你在自便函数之间自由切换,而不需把这一个函数先注明为generator。

from greenlet import greenlet

def test1():
    print('test1,first')
    gr2.switch()
    print('test1,sencod')
    gr2.switch()
def test2():
    print('test2,first')
    gr1.switch()
    print('test2,sencod')


gr1=greenlet(test1)
gr2=greenlet(test2)
gr1.switch()
'''
执行结果:
test1,first
test2,first
test1,sencod
test2,sencod
'''

澳门葡京备用网址 89澳门葡京备用网址 90

from greenlet import greenlet
def eat(name):
    print('%s eat fruit apple' %name)
    gr2.switch('shuke')
    print('%s eat fruit banana' %name)
    gr2.switch()
def play_phone(name):
    print('%s play basketbal' %name)
    gr1.switch()
    print('%s play football' %name)

gr1=greenlet(eat)
gr2=greenlet(play_phone)
gr1.switch(name='jack')  #可以在第一次switch时传入参数,以后都不需要

'''
执行结果:
jack eat fruit apple
shuke play basketbal
jack eat fruit banana
shuke play football
'''

switch传参

唯有的切换(在尚未io的情事下还是没有再度开垦内部存款和储蓄器空间的操作),反而会减低程序的进行进程。

澳门葡京备用网址 91澳门葡京备用网址 92

#顺序执行
import time
def f1():
    res=0
    for i in range(10000000):
        res+=i

def f2():
    res=0
    for i in range(10000000):
        res*=i


start_time=time.time()
f1()
f2()
stop_time=time.time()
print('run time is: %s' %(stop_time-start_time)) #1.7395639419555664


#切换
from greenlet import greenlet
import time
def f1():
    res=0
    for i in range(10000000):
        res+=i
        gr2.switch()


def f2():
    res=0
    for i in range(10000000):
        res*=i
        gr1.switch()

gr1=greenlet(f1)
gr2=greenlet(f2)

start_time=time.time()
gr1.switch()
stop_time=time.time()
print('run time is: %s' %(stop_time-start_time)) #7.789067983627319

示例

greenlet只是提供了壹种比generator尤其便利的切换方式,依旧是从未有过缓慢解决蒙受IO自动切换的难点。

 

1.1陆 数值类型

1.一五 存款和储蓄引擎

储引擎即表类型,mysql依照分歧的表类型会有两样的管理机制

查看引擎

show engines;

 

创建引擎

create table t1(id int)engine=innodb;

create table t2(id int)engine=myisam;

create table t3(id int)engine=memory;

create table t4(id int)engine=blackhole;

 

 

 1 #继承Thread式创建
 2 
 3 import threading
 4 import time
 5 
 6 class MyThread(threading.Thread):
 7 
 8     def __init__(self,num):
 9         threading.Thread.__init__(self)    #继承父类__init__
10         self.num=num
11 
12     def run(self):    #必须定义run方法
13         print("running on number:%s" %self.num)
14         time.sleep(3)
15 
16 t1=MyThread(56)
17 t2=MyThread(78)
18 
19 t1.start()
20 t2.start()
21 print("ending")

伍. gevent模块(单线程并发)

Gevent
是三个第3方库,能够轻易通过gevent完结产出同步或异步编程,在gevent中用到的基本点形式是Greenlet,
它是以C扩充模块情势接入Python的轻量级协程。
格林let全部运作在主程序操作系统进程的内部,但它们被同盟式地调解。

g壹=gevent.spawn()创立三个体协会程对象g一,spawn括号内首先个参数是函数名,如eat,后边能够有三个参数,能够是岗位实参或入眼字实参,都以传给函数eat的。

蒙受IO阻塞时会自动切换任务

import gevent

def eat():
    print('eat food 1')
    gevent.sleep(2)     # 等饭来
    print('eat food 2')

def play_phone():
    print('play phone 1')
    gevent.sleep(1)     # 网卡了
    print('play phone 2')

# gevent.spawn(eat)
# gevent.spawn(play_phone)
# print('主')  # 直接结束

# 因而也需要join方法,进程或线程的jion方法只能join一个,而gevent的join方法可以join多个
g1=gevent.spawn(eat)
g2=gevent.spawn(play_phone)
gevent.joinall([g1,g2])
print('主')

'''
执行结果:
eat food 1
play phone 1
play phone 2
eat food 2
主
'''

注:
上例中gevent.sleep(二)模拟的是gevent能够辨别的io阻塞,而time.sleep(2)或其余的隔开分离,gevent是不能够直接识别的,此时就必要张开打补丁,将卡住设置为gevent能够辨其余IO阻塞。

通常的写法为,在文件的起来,如下

from gevent import monkey;monkey.patch_all()
import gevent
import time

澳门葡京备用网址 93澳门葡京备用网址 94

from gevent import monkey;monkey.patch_all()

import gevent
import time


def eat():
    print('eat food 1')
    time.sleep(2)
    print('eat food 2')

def play_phone():
    print('play phone 1')
    time.sleep(1)
    print('play phone 2')



g1=gevent.spawn(eat)
g2=gevent.spawn(play_phone)
gevent.joinall([g1,g2])
print('主')

示例

联合与异步

概念:

共同和异步的概念对于许三个人的话是二个模糊的定义,是一种仿佛只可以意会不能够言传的事物。其实我们的生存中留存着多数共同异步的例证。比方:你叫自个儿去用餐,小编听到了就马上和你去就餐,假使我们有视听,你就会向来叫小编,直到本身听见和你共同去就餐,这么些进程叫联合;异步进度指你叫本人去用餐,然后您就去用餐了,而不论是小编是否和你一块去吃饭。而我收获新闻后可能及时就走,也恐怕过段时间再走。尽管作者请您吃饭,便是二只,假设你请小编吃饭就用异步,那样你比较省钱。哈哈哈。。。

import gevent

def task(pid):
    """
    Some non-deterministic task
    """
    gevent.sleep(0.5)
    print('Task %s done' % pid)

def synchronous():
    for i in range(1, 10):
        task(i)

def asynchronous():
    threads = [gevent.spawn(task, i) for i in range(10)]
    gevent.joinall(threads)

print('Synchronous:')
synchronous()       # 同步

print('Asynchronous:')
asynchronous()      # 异步

上边程序的主要部分是将task函数封装到格林let内部线程的gevent.spawn
起先化的greenlet列表存放在数组threads中,此列表被传给gevent.joinall 函数,后者阻塞当前流程,并推行全体给定的greenlet。实践流程只会在
全体greenlet试行完后才会一连向下走。

#gevent线程的一些用法
g1=gevent.spawn(func,1,,2,3,x=4,y=5)
g2=gevent.spawn(func2)
g1.join() #等待g1结束
g2.join() #等待g2结束
#或者上述两步合作一步:gevent.joinall([g1,g2])
g1.value#拿到func1的返回值

澳门葡京备用网址 95澳门葡京备用网址 96

from gevent import monkey;monkey.patch_all()
import gevent
import requests
import time

def get_page(url):
    print('GET: %s' %url)
    response=requests.get(url)
    if response.status_code == 200:
        print('%d bytes received from %s' %(len(response.text),url))


start_time=time.time()
gevent.joinall([
    gevent.spawn(get_page,'https://www.python.org/'),
    gevent.spawn(get_page,'https://www.yahoo.com/'),
    gevent.spawn(get_page,'https://github.com/'),
])
stop_time=time.time()
print('run time is %s' %(stop_time-start_time))

协程应用:爬虫

协程应用(爬虫)

透过gevent落成单线程下的socket并发(from gevent import
monkey;monkey.patch_all()一定要放权导入socket模块在此以前,不然gevent不可能辨认socket的围堵)

澳门葡京备用网址 97澳门葡京备用网址 98

from gevent import monkey;monkey.patch_all()
from socket import *
import gevent

#如果不想用money.patch_all()打补丁,可以用gevent自带的socket
# from gevent import socket
# s=socket.socket()

def server(server_ip,port):
    s=socket(AF_INET,SOCK_STREAM)
    s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
    s.bind((server_ip,port))
    s.listen(5)
    while True:
        conn,addr=s.accept()
        gevent.spawn(talk,conn,addr)

def talk(conn,addr):
    try:
        while True:
            res=conn.recv(1024)
            print('client %s:%s msg: %s' %(addr[0],addr[1],res))
            conn.send(res.upper())
    except Exception as e:
        print(e)
    finally:
        conn.close()

if __name__ == '__main__':
    server('127.0.0.1',8080)

服务端

澳门葡京备用网址 99澳门葡京备用网址 100

#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'

from socket import *

client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))


while True:
    msg=input('>>: ').strip()
    if not msg:continue

    client.send(msg.encode('utf-8'))
    msg=client.recv(1024)
    print(msg.decode('utf-8'))

客户端

澳门葡京备用网址 101澳门葡京备用网址 102

from threading import Thread
from socket import *
import threading

def client(server_ip,port):
    c=socket(AF_INET,SOCK_STREAM)
    c.connect((server_ip,port))

    count=0
    while True:
        c.send(('%s say hello %s' %(threading.current_thread().getName(),count)).encode('utf-8'))
        msg=c.recv(1024)
        print(msg.decode('utf-8'))
        count+=1
if __name__ == '__main__':
    for i in range(500):
        t=Thread(target=client,args=('127.0.0.1',8080))
        t.start()

三十二线程并发多个客户端

 

一.1六.一 整型(私下认可有号子)

create table t8(n tinyint);

insert into t8 values(-1);

insert into t8 values(128);

insert into t8 values(-129);



create table t9(n tinyint unsigned);

insert into t9 values(-1),(256);

 

 

#整型的幅度代表显示上涨的幅度

create table t11(n int(3) unsigned zerofill);

create table t12(n int unsigned zerofill);



create table t13(

    id int

);

 

 

 

 

一.1六 数值类型

View Code

陆. 综合使用

简单的讲主机批量管理工科具

需求:

  1. 主机分组
  2. 主机信息配置文件用configparser解析
  3. 可批量推行命令、发送文书,结果实时重返,实行格式如下 
    1. batch_run  -h h1,h2,h3   -g web_clusters,db_servers    -cmd
       “df -h” 
    2. batch_scp   -h h1,h2,h3   -g web_clusters,db_servers  -action
      put  -local test.py  -remote /tmp/ 
  4. 主机用户名密码、端口能够分歧
  5. 实行长途命令使用paramiko模块
  6. 批量发令需利用multiprocessing并发

code: https://github.com/shuke163/learnpy/tree/master/homework/day09/managetool 

 

 

 

 

 

 

 

比较之下学习参考:

  1.   https://tracholar.github.io/wiki/python/python-multiprocessing-tutorial.html

2.
  

 

 

 

 

 

 

1.16.2 浮点型

create table t13(x float(255,30));

create table t14(x double(255,30));

create table t15(x decimal(65,30));





insert into t13 values(1.111111111111111111111111111111);

insert into t14 values(1.111111111111111111111111111111);

insert into t15 values(1.111111111111111111111111111111);

 

 

1.1陆.一 整型(默许有标记)

create table t8(n tinyint);

insert into t8 values(-1);

insert into t8 values(128);

insert into t8 values(-129);



create table t9(n tinyint unsigned);

insert into t9 values(-1),(256);

 

 

#整型的宽度代表展现上升的幅度

create table t11(n int(3) unsigned zerofill);

create table t12(n int unsigned zerofill);



create table t13(

    id int

);

 

 

 

 

叁. Thread类的实例方法

一.一7 日期类型

create table student(

    id int,

    name char(16),

    born_year year,

    birth_date date,

    class_time time,

    reg_time datetime

);



insert into student values

(1,'egon',now(),now(),now(),now())

;



insert into student values

(2,'alex','1999','1999-11-11','11:11:11',"1999-11-11 11:11:11")

 

 

1.16.2 浮点型

create table t13(x float(255,30));

create table t14(x double(255,30));

create table t15(x decimal(65,30));





insert into t13 values(1.111111111111111111111111111111);

insert into t14 values(1.111111111111111111111111111111);

insert into t15 values(1.111111111111111111111111111111);

 

 

join和dameon

一.1八 字符类型

char:定长

varchar:变长

 

#步长代表的是字符的个数

create table t16(name char(5));

create table t17(name varchar(5));



insert into t16 values('李杰 '); #'李杰   '

insert into t17 values('李杰 '); #'李杰 '



select char_length(name) from t16; #5

select char_length(name) from t17; #3



mysql> set sql_mode='PAD_CHAR_TO_FULL_LENGTH';



select * from t16 where name='李杰';

select * from t17 where name='李杰';



select * from t16 where name like '李杰';



name char(5)

egon |alex |wxx  |





name varchar(5)

1bytes+egon|1bytes+alex|1bytes+wxx|

 

一.壹7 日期类型

create table student(

    id int,

    name char(16),

    born_year year,

    birth_date date,

    class_time time,

    reg_time datetime

);



insert into student values

(1,'egon',now(),now(),now(),now())

;



insert into student values

(2,'alex','1999','1999-11-11','11:11:11',"1999-11-11 11:11:11")

 

 

澳门葡京备用网址 103澳门葡京备用网址 104

一.1九 枚举类型与集中类型

create table employee(

    id int,

    name char(10),

    sex enum('male','female','other'),

    hobbies set('play','eat','music','read')

);



insert into employee values

(1,'egon','male','music,read');



insert into employee values

(2,'alex','xxxx','music,read');

 

一.18 字符类型

char:定长

varchar:变长

 

#宽窄代表的是字符的个数

create table t16(name char(5));

create table t17(name varchar(5));



insert into t16 values('李杰 '); #'李杰   '

insert into t17 values('李杰 '); #'李杰 '



select char_length(name) from t16; #5

select char_length(name) from t17; #3



mysql> set sql_mode='PAD_CHAR_TO_FULL_LENGTH';



select * from t16 where name='李杰';

select * from t17 where name='李杰';



select * from t16 where name like '李杰';



name char(5)

egon |alex |wxx  |





name varchar(5)

1bytes+egon|1bytes+alex|1bytes+wxx|

 

 1 import threading
 2 from time import ctime,sleep
 3 
 4 def Music(name):
 5 
 6         print ("Begin listening to {name}. {time}".format(name=name,time=ctime()))
 7         sleep(3)
 8         print("end listening {time}".format(time=ctime()))
 9 
10 def Blog(title):
11 
12         print ("Begin recording the {title}. {time}".format(title=title,time=ctime()))
13         sleep(5)
14         print('end recording {time}'.format(time=ctime()))
15 
16 
17 threads = []
18 
19 
20 t1 = threading.Thread(target=Music,args=('FILL ME',))
21 t2 = threading.Thread(target=Blog,args=('',))
22 
23 threads.append(t1)
24 threads.append(t2)
25 
26 if __name__ == '__main__':
27 
28     #t2.setDaemon(True)
29 
30     for t in threads:
31 
32         #t.setDaemon(True) #注意:一定在start之前设置
33         t.start()
34 
35         #t.join()
36 
37     #t1.join()
38     #t2.join()    #  考虑这三种join位置下的结果?
39 
40     print ("all over %s" %ctime())

壹.1九 枚举类型与聚焦类型

create table employee(

    id int,

    name char(10),

    sex enum('male','female','other'),

    hobbies set('play','eat','music','read')

);



insert into employee values

(1,'egon','male','music,read');



insert into employee values

(2,'alex','xxxx','music,read');

 

1.一 三十二线程在价值观操作系统中,各个进程有二个地方空间,而且私下认可就有多少个调节线程
线程顾名思义,就…

join和setDaemon

别的方法:

1 Thread实例对象的方法
2   # isAlive(): 返回线程是否活动的。
3   # getName(): 返回线程名。
4   # setName(): 设置线程名。
5 
6 threading模块提供的一些方法:
7   # threading.currentThread(): 返回当前的线程变量。
8   # threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
9   # threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

六、GIL

'''

定义:
In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple 
native threads from executing Python bytecodes at once. This lock is necessary mainly 
because CPython’s memory management is not thread-safe. (However, since the GIL 
exists, other features have grown to depend on the guarantees that it enforces.)

'''

Python中的线程是操作系统的原生线程,Python虚拟机使用一个大局解释器锁(Global
Interpreter
Lock)来互斥线程对Python虚拟机的使用。为了援助十二线程机制,2其中坚的渴求便是急需落成分裂线程对共享财富访问的排外,所以引进了GIL。
GIL:在1个线程具有领会释器的访问权之后,其余的有着线程都必须等待它释放解释器的访问权,即便这么些线程的下一条指令并不会相互影响。
在调用任何Python C API以前,要先获得GIL
GIL缺点:多管理器退化为单管理器;优点:防止大批量的加锁解锁操作。

一.
GIL的最初设计

Python补助拾二线程,而消除十2线程之间数据完整性和气象同步的最简便易行方法自然就是加锁。
于是有了GIL那把拔尖大锁,而当越多的代码库开采者接受了那种设定后,他们发轫大批量借助那种天性(即私下认可python内部对象是thread-safe的,无需在促成时思量外加的内部存款和储蓄器锁和同步操作)。渐渐的那种实现方式被开采是蛋疼且低效的。但当大家总结去拆分和去除GIL的时候,开掘多量库代码开拓者现已重度重视GIL而尤其难以去除了。有多难?做个类比,像MySQL那样的“小项目”为了把Buffer
Pool
Mutex那把大锁拆分成各种小锁也花了从伍.5到五.六再到5.七几个大版为期近五年的时间,并且仍在此起彼伏。MySQL那些背后有合营社帮助且有稳固支出公司的成品走的那样难堪,这又加以Python那样主旨开垦和代码进献者中度社区化的组织吗?

2.
GIL的影响

无论你启多少个线程,你有多少个cpu,
Python在推行二个历程的时候会淡定的在平等时刻只同意三个线程运转。
为此,python是心有余而力不足利用多核CPU落成二十四线程的。
这么,python对于总计密集型的职责开十二线程的频率以致不比串行(未有大气切换),然而,对于IO密集型的天职效用依然有总之进级的。

澳门葡京备用网址 105

总结密集型实例:

澳门葡京备用网址 106澳门葡京备用网址 107

 1 #coding:utf8
 2 from threading import Thread
 3 import time
 4 
 5 def counter():
 6     i = 0
 7     for _ in range(100000000):
 8         i = i + 1
 9     return True
10 
11 
12 def main():
13     l=[]
14     start_time = time.time()
15     for i in range(2):
16 
17         t = Thread(target=counter)
18         t.start()
19         l.append(t)
20         t.join()
21 
22     for t in l:
23         t.join()
24     # counter()
25     # counter()
26     end_time = time.time()
27     print("Total time: {}".format(end_time - start_time))
28 
29 if __name__ == '__main__':
30     main()
31 
32 
33 '''
34 py2.7:
35      串行:9.17599987984s
36      并发:9.26799988747s
37 py3.6:
38      串行:9.540389776229858s
39      并发:9.568442583084106s
40 
41 '''

算算密集型,二十102线程并发相比较串行,未有强烈优势

三. 缓慢解决方案

用multiprocessing代替Thread
multiprocessing库的面世相当的大程度上是为着弥补thread库因为GIL而失效的瑕疵。它完全的复制了一套thread所提供的接口方便迁移。唯一的例外正是它使用了多进度而不是十贰线程。种种进度有自身的单独的GIL,由此也不相会世进度之间的GIL争抢。

澳门葡京备用网址 108澳门葡京备用网址 109

 1 #coding:utf8
 2 from multiprocessing import Process
 3 import time
 4 
 5 def counter():
 6     i = 0
 7     for _ in range(100000000):
 8         i = i + 1
 9 
10     return True
11 
12 def main():
13 
14     l=[]
15     start_time = time.time()
16 
17     # for _ in range(2):
18     #     t=Process(target=counter)
19     #     t.start()
20     #     l.append(t)
21     #     #t.join()
22     #
23     # for t in l:
24     #    t.join()
25     counter()
26     counter()
27     end_time = time.time()
28     print("Total time: {}".format(end_time - start_time))
29 
30 if __name__ == '__main__':
31     main()
32 
33 
34 '''
35 
36 py2.7:
37      串行:8.92299985886 s
38      并行:8.19099998474 s
39 
40 py3.6:
41      串行:9.963459014892578 s
42      并发:5.1366541385650635 s
43 
44 '''

multiprocess多进程落成并发运算能够进步效能

理所当然multiprocessing也不是万能良药。它的引进会加多程序达成时线程间数据通信和共同的好多不便。就拿计数器来比如子,借使大家要三个线程累加同二个变量,对于thread来说,申雅培个global变量,用thread.Lock的context包裹住,3行就解决了。而multiprocessing由于经过之间不大概见到对方的多少,只可以通过在主线程注脚一个Queue,put再get或许用share
memory的章程。这一个额外的完结资本使得本来就丰富难受的三十二线程程序编码,变得特别痛苦了。

总计:因为GIL的存在,唯有IO
Bound场景下的10二线程会获得较好的性质提高;若是对并行总括质量较高的次序能够考虑把大旨部分改为C模块,大概几乎用别的语言达成;GIL在较长1段时间内将会持续存在,然则会持续对其实行修正。

七、同步锁(lock)

10贰线程和多进程最大的不等在于,多进度中,同三个变量,各自有一份拷贝存在于各类进度中,互不影响,而二十四线程中,全体变量都由全体线程共享,所以,任何二个变量都足以被其余八个线程修改,因而,线程之间共享数据最大的摇摇欲倒在于多少个线程同时改3个变量,把内容给改乱了。

澳门葡京备用网址 110澳门葡京备用网址 111

 1 import time
 2 import threading
 3 
 4 def subNum():
 5     global num #在每个线程中都获取这个全局变量
 6     temp = num
 7     time.sleep(0.1)
 8     num =temp-1  # 对此公共变量进行-1操作
 9 
10 num = 100  #设定一个共享变量
11 thread_list = []
12 
13 for i in range(100):
14     t = threading.Thread(target=subNum)
15     t.start()
16     thread_list.append(t)
17 
18 for t in thread_list: #等待所有线程执行完毕
19     t.join()
20 
21 print('Result: ', num)
22 
23 
24 #运行结果:
25 #Result:  99

二10四线程共享变量,无法确定保证变量安全

如上实例,在3个进程内,设置共享变量num=拾0,然后成立99个线程,实践num-=①的操作,不过,由于在函数subNum中设有time.sleep(0.1),该语句能够等价于IO操作。于是在那短小0.壹秒的小时内,全部的线程已经创制并运营,得到了num=十0的变量,等待0.1秒过后,最后获得的num其实是9玖.

锁平日被用来贯彻对共享能源的联合具名访问。为每2个共享财富创设1个Lock对象,当你要求拜访该能源时,调用acquire方法来获取锁对象(倘若别的线程已经获得了该锁,则当前线程需等待其被放出),待能源访问完后,再调用release方法释放锁:

澳门葡京备用网址 112澳门葡京备用网址 113

 1 import time
 2 import threading
 3 
 4 def subNum():
 5     global num #在每个线程中都获取这个全局变量
 6     lock.acquire()
 7     temp = num
 8     time.sleep(0.1)
 9     num =temp-1  # 对此公共变量进行-1操作
10     lock.release()
11 
12 
13 num = 100  #设定一个共享变量
14 lock = threading.Lock()    #生成一个同步锁对象
15 thread_list = []
16 
17 for i in range(100):
18     t = threading.Thread(target=subNum)
19     t.start()
20     thread_list.append(t)
21 
22 for t in thread_list: #等待所有线程执行完毕
23     t.join()
24 
25 print('Result: ', num)
26 
27 #运行结果:
28 #Result:  0

运用lock方法,保险变量安全

 

lock.acquire()与lock.release()包起来的代码段,保证平等时刻只允许二个线程引用。

1 import threading
2 
3 R=threading.Lock()
4 
5 R.acquire()
6 '''
7 对公共数据的操作
8 '''
9 R.release()

8、死锁与递归锁

所谓死锁:
是指多个或三个以上的经过或线程在举办进程中,因争夺能源而招致的壹种互动等待的气象,若无外力效用,它们都将无法推进下去。此时称系统处于死锁状态或系统一发布出了死锁,那几个恒久在竞相等待的长河称为死锁进度。

澳门葡京备用网址 114澳门葡京备用网址 115

 1 import threading
 2 import time
 3 
 4 mutexA = threading.Lock()
 5 mutexB = threading.Lock()
 6 
 7 class MyThread(threading.Thread):
 8 
 9     def __init__(self):
10         threading.Thread.__init__(self)
11 
12     def run(self):
13         self.fun1()
14         self.fun2()
15 
16     def fun1(self):
17 
18         mutexA.acquire()  # 如果锁被占用,则阻塞在这里,等待锁的释放
19 
20         print("I am %s , get res: %s---%s" %(self.name, "ResA",time.time()))
21 
22         mutexB.acquire()
23         print("I am %s , get res: %s---%s" %(self.name, "ResB",time.time()))
24         mutexB.release()
25 
26         mutexA.release()
27 
28 
29     def fun2(self):
30 
31         mutexB.acquire()
32         print("I am %s , get res: %s---%s" %(self.name, "ResB",time.time()))
33         time.sleep(0.2)
34 
35         mutexA.acquire()
36         print("I am %s , get res: %s---%s" %(self.name, "ResA",time.time()))
37         mutexA.release()
38 
39         mutexB.release()
40 
41 if __name__ == "__main__":
42 
43     print("start---------------------------%s"%time.time())
44 
45     for i in range(0, 10):
46         my_thread = MyThread()
47         my_thread.start()
48 
49 
50 
51 #运行结果:
52 #start---------------------------1494316634.4121563
53 #I am Thread-1 , get res: ResA---1494316634.4121563
54 #I am Thread-1 , get res: ResB---1494316634.4121563
55 #I am Thread-1 , get res: ResB---1494316634.4121563
56 #I am Thread-2 , get res: ResA---1494316634.4121563

死锁实例

 

在Python中为了支持在同1线程中再叁伸手同一财富,python提供了可重入锁昂CoraLock。这些科雷傲Lock内部维护着二个Lock和一个counter变量,counter记录了acquire的次数,从而使得财富能够被反复require。直到三个线程全数的acquire都被release,别的的线程本领获得财富。上边的例子假如运用OdysseyLock取代Lock,则不会爆发死锁:

澳门葡京备用网址 116澳门葡京备用网址 117

 1 import threading
 2 import time
 3 
 4 # mutexA = threading.Lock()
 5 # mutexB = threading.Lock()
 6 rlock = threading.RLock()
 7 
 8 class MyThread(threading.Thread):
 9 
10     def __init__(self):
11         threading.Thread.__init__(self)
12 
13     def run(self):
14         self.fun1()
15         self.fun2()
16 
17     def fun1(self):
18         rlock.acquire()  # 如果锁被占用,则阻塞在这里,等待锁的释放
19 
20         print("I am %s , get res: %s---%s" %(self.name, "ResA",time.time()))
21 
22         rlock.acquire()
23         print("I am %s , get res: %s---%s" %(self.name, "ResB",time.time()))
24         rlock.release()
25 
26         rlock.release()
27 
28 
29     def fun2(self):
30         rlock.acquire()
31         print("I am %s , get res: %s---%s" %(self.name, "ResB",time.time()))
32         time.sleep(0.2)
33 
34         rlock.acquire()
35         print("I am %s , get res: %s---%s" %(self.name, "ResA",time.time()))
36         rlock.release()
37 
38         rlock.release()
39 
40 if __name__ == "__main__":
41 
42     print("start---------------------------%s"%time.time())
43 
44     for i in range(0, 10):
45         my_thread = MyThread()
46         my_thread.start()
47 
48 
49 #运行结果:从以下结果也可以发现,线程之间是竞争关系
50 """
51 start---------------------------1494316940.0863945
52 I am Thread-1 , get res: ResA---1494316940.0873976
53 I am Thread-1 , get res: ResB---1494316940.0873976
54 I am Thread-1 , get res: ResB---1494316940.0873976
55 I am Thread-1 , get res: ResA---1494316940.287911
56 I am Thread-2 , get res: ResA---1494316940.287911
57 I am Thread-2 , get res: ResB---1494316940.287911
58 I am Thread-2 , get res: ResB---1494316940.287911
59 I am Thread-2 , get res: ResA---1494316940.4883447
60 I am Thread-4 , get res: ResA---1494316940.4883447
61 I am Thread-4 , get res: ResB---1494316940.4883447
62 I am Thread-4 , get res: ResB---1494316940.4883447
63 I am Thread-4 , get res: ResA---1494316940.6886203
64 I am Thread-6 , get res: ResA---1494316940.6886203
65 I am Thread-6 , get res: ResB---1494316940.6896234
66 I am Thread-6 , get res: ResB---1494316940.6896234
67 I am Thread-6 , get res: ResA---1494316940.890659
68 I am Thread-8 , get res: ResA---1494316940.890659
69 I am Thread-8 , get res: ResB---1494316940.890659
70 I am Thread-8 , get res: ResB---1494316940.890659
71 I am Thread-8 , get res: ResA---1494316941.0918815
72 I am Thread-10 , get res: ResA---1494316941.0918815
73 I am Thread-10 , get res: ResB---1494316941.0918815
74 I am Thread-10 , get res: ResB---1494316941.0918815
75 I am Thread-10 , get res: ResA---1494316941.2923715
76 I am Thread-5 , get res: ResA---1494316941.2923715
77 I am Thread-5 , get res: ResB---1494316941.2923715
78 I am Thread-5 , get res: ResB---1494316941.2923715
79 I am Thread-5 , get res: ResA---1494316941.493138
80 I am Thread-9 , get res: ResA---1494316941.493138
81 I am Thread-9 , get res: ResB---1494316941.493138
82 I am Thread-9 , get res: ResB---1494316941.493138
83 I am Thread-9 , get res: ResA---1494316941.6937861
84 I am Thread-7 , get res: ResA---1494316941.6937861
85 I am Thread-7 , get res: ResB---1494316941.6937861
86 I am Thread-7 , get res: ResB---1494316941.6937861
87 I am Thread-7 , get res: ResA---1494316941.8946414
88 I am Thread-3 , get res: ResA---1494316941.8946414
89 I am Thread-3 , get res: ResB---1494316941.8946414
90 I am Thread-3 , get res: ResB---1494316941.8946414
91 I am Thread-3 , get res: ResA---1494316942.0956843
92 """

递归锁消除死锁

九、event对象

线程的3个主要本性是各种线程都以独立运作且景况不行预测。假使程序中的其余线程须要通过判定有些线程的事态来规定本人下一步的操作,那时线程同步难题就会变得相当困难。为了化解这个标题,我们须求采取threading库中的伊芙nt对象。对象涵盖二个可由线程设置的复信号标识,它同意线程等待某个事件的发出。在开始处境下,伊夫nt对象中的信号标记被安装为False。如若无线程等待二个伊夫nt对象,
而那几个伊夫nt对象的标识为False,那么这一个线程将会被一向不通直至该标记为True。3个线程假诺将3个伊夫nt对象的时限信号标记设置为True,它将唤起全部等待那些伊芙nt对象的线程。倘诺多个线程等待多少个曾经被设置为真正伊芙nt对象,那么它将忽略那几个事件,
继续实施。

event.isSet():返回event的状态值;

event.wait():如果 event.isSet()==False将阻塞线程;

event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;

event.clear():恢复event的状态值为False。

澳门葡京备用网址 118

 

能够思考壹种选用场景(仅仅作为注脚),比方,大家有四个线程从Redis队列中读取数据来拍卖,那么些线程都要尝试去连接Redis的服务,一般意况下,如果Redis连接不成功,在所有人家线程的代码中,都会去尝试再一次连接。假若我们想要在运转时确认保证Redis服务符合规律,才让那个职业线程去连接Redis服务器,那么大家就足以动用threading.伊芙nt机制来和谐各类工作线程的连年操作:主线程中会去尝尝连接Redis服务,假设平常的话,触发事件,各专业线程会尝试连接Redis服务。

澳门葡京备用网址 119澳门葡京备用网址 120

 1 import threading
 2 import time
 3 import logging
 4 
 5 logging.basicConfig(level=logging.DEBUG, format='(%(threadName)-10s) %(message)s',)
 6 
 7 def worker(event):
 8     logging.debug('Waiting for redis ready...')
 9     while not event.isSet():
10         logging.debug('connect failed...')
11         event.wait(1)
12     logging.debug('redis ready, and connect to redis server and do some work [%s]', time.ctime())
13     time.sleep(1)
14 
15 def main():
16     readis_ready = threading.Event()
17     t1 = threading.Thread(target=worker, args=(readis_ready,), name='t1')
18     t1.start()
19 
20     t2 = threading.Thread(target=worker, args=(readis_ready,), name='t2')
21     t2.start()
22 
23     logging.debug('first of all, check redis server, make sure it is OK, and then trigger the redis ready event')
24     time.sleep(3) # simulate the check progress
25     logging.debug('redis server is running')
26     readis_ready.set()
27 
28 if __name__=="__main__":
29     main()
30 
31 
32 #运行结果:
33 (t1        ) Waiting for redis ready...
34 # (t1        ) connect failed...
35 # (t2        ) Waiting for redis ready...
36 # (t2        ) connect failed...
37 # (MainThread) first of all, check redis server, make sure it is OK, and then trigger the redis ready event
38 # (t1        ) connect failed...
39 # (t2        ) connect failed...
40 # (t2        ) connect failed...
41 # (t1        ) connect failed...
42 # (MainThread) redis server is running
43 # (t2        ) redis ready, and connect to redis server and do some work [Tue May  9 16:15:18 2017]
44 # (t1        ) redis ready, and connect to redis server and do some work [Tue May  9 16:15:18 2017]

监听Redis服务

十、Semaphore(信号量)

Semaphore管理一个平放的计数器,
每当调用acquire()时内置计数器-1;
调用release() 时内置计数器+一;
计数器不可能小于0;当计数器为0时,acquire()将封堵线程直到别的线程调用release()。

实例:(同时只有6个线程能够取得semaphore,即能够界定最第Billy斯接数为五):

澳门葡京备用网址 121澳门葡京备用网址 122

 1 import threading
 2 import time
 3 
 4 semaphore = threading.Semaphore(5)
 5 
 6 def func():
 7     if semaphore.acquire():
 8         print (threading.currentThread().getName() + ' get semaphore')
 9         time.sleep(2)
10         semaphore.release()
11 
12 for i in range(20):
13   t1 = threading.Thread(target=func)
14   t1.start()
15 
16 
17 #运行结果:
18 # Thread-1 get semaphore
19 # Thread-2 get semaphore
20 # Thread-3 get semaphore
21 # Thread-4 get semaphore
22 # Thread-5 get semaphore
23 # Thread-6 get semaphore#隔2秒打印
24 # Thread-7 get semaphore
25 # Thread-8 get semaphore
26 # Thread-9 get semaphore
27 # Thread-10 get semaphore
28 # Thread-11 get semaphore#隔2秒打印
29 # Thread-12 get semaphore
30 # Thread-13 get semaphore
31 # Thread-14 get semaphore
32 # Thread-15 get semaphore
33 # Thread-16 get semaphore#隔2秒打印
34 # Thread-17 get semaphore
35 # Thread-18 get semaphore
36 # Thread-20 get semaphore
37 # Thread-19 get semaphore

semaphore实例

十一、multiprocessing

Multiprocessing is a package that supports spawning processes using an API similar to the threading module. 
The multiprocessing package offers both local and remote concurrency,effectively side-stepping the Global Interpreter Lock by using subprocesses instead of threads. 
Due to this, the multiprocessing module allows the programmer to fully leverage multiple processors on a given machine. It runs on both Unix and Windows.

 

鉴于GIL的存在,python中的二十四线程其实并不是真的的二十四线程,若是想要丰硕地使用多核CPU的财富,在python中大多处境要求利用多进度。

multiprocessing包是python中的多进度管理包。与threading.Thread类似,它能够行使multiprocessing.Process对象来创设三个进度。该进度能够运营在Python程序内部编写的函数。该Process对象与Thread对象的用法同样,也有start(),
run(),
join()的章程。别的multiprocessing包中也有Lock/伊芙nt/Semaphore/Condition类
(那几个目标可以像多线程这样,通过参数字传送递给各类进度),用以同步进度,其用法与threading包中的同名类1致。所以,multiprocessing的相当大学一年级部份与threading使用同样套API,只不过换来了多进度的情境。

澳门葡京备用网址 123澳门葡京备用网址 124

 1 from multiprocessing import Process
 2 import time
 3 def f(name):
 4 
 5     print('hello', name,time.ctime())
 6     time.sleep(1)
 7 
 8 if __name__ == '__main__':
 9     p_list=[]
10     for i in range(3):
11         p = Process(target=f, args=('alvin:%s'%i,))
12         p_list.append(p)
13         p.start()
14     for i in p_list:
15         p.join()
16     print('end')
17 
18 
19 #运行结果:
20 #hello alvin:0 Tue May  9 16:41:18 2017
21 #hello alvin:1 Tue May  9 16:41:18 2017
22 #hello alvin:2 Tue May  9 16:41:18 2017
23 #end

Process类调用

 

 

澳门葡京备用网址 125澳门葡京备用网址 126

 1 from multiprocessing import Process
 2 import time
 3 
 4 class MyProcess(Process):
 5     def __init__(self):
 6         super(MyProcess, self).__init__()
 7 
 8     def run(self):
 9 
10         print ('hello', self.name,time.ctime())
11         time.sleep(1)
12 
13 
14 if __name__ == '__main__':
15     p_list=[]
16     for i in range(3):
17         p = MyProcess()
18         p.start()
19         p_list.append(p)
20 
21     for p in p_list:
22         p.join()
23 
24     print('end')
25 
26 
27 #运行结果:
28 #hello MyProcess-1 Tue May  9 16:42:46 2017
29 #hello MyProcess-2 Tue May  9 16:42:46 2017
30 #hello MyProcess-3 Tue May  9 16:42:46 2017
31 #end

继承Process类调用

process类:

构造方法:

Process([group [, target [, name [, args [, kwargs]]]]])

  group: 线程组,方今还从来不兑现,库引用中提醒必须是None; 
  target: 要实行的点子; 
  name: 进程名; 
  args/kwargs: 要传入方法的参数。

实例方法:

  is_alive():重返进度是还是不是在运营。

  join([timeout]):阻塞当前上下文处境的进程程,直到调用此办法的经过终止或达到内定的timeout(可选参数)。

  start():进程打算稳当,等待CPU调解

  run():strat()调用run方法,假使实例进度时未制定传入target,那star试行t私下认可run()方法。

  terminate():不管任务是还是不是成功,马上终止专门的学问进程

属性:

  daemon:和线程的setDeamon功效雷同

  name:进程名字。

  pid:进程号。

实例:

澳门葡京备用网址 127澳门葡京备用网址 128

 1 from multiprocessing import Process
 2 import os
 3 import time
 4 def info(name):
 5 
 6 
 7     print("name:",name)
 8     print('parent process:', os.getppid())
 9     print('process id:', os.getpid())
10     print("------------------")
11     time.sleep(1)
12 
13 def foo(name):
14 
15     info(name)
16 
17 if __name__ == '__main__':
18 
19     info('main process line')
20 
21 
22     p1 = Process(target=info, args=('alvin',))
23     p2 = Process(target=foo, args=('egon',))
24     p1.start()
25     p2.start()
26 
27     p1.join()
28     p2.join()
29 
30     print("ending")
31 
32 
33 
34 #运行结果:
35 # name: main process line
36 # parent process: 5112
37 # process id: 10808
38 # ------------------
39 # name: alvin
40 # name: egon
41 # parent process: 10808
42 # process id: 9576
43 # ------------------
44 # parent process: 10808
45 # process id: 9604
46 # ------------------
47 # ending

process类创立多进程

透过tasklist(Win)可能ps -elf
|grep(linux)命令检查实验每贰个历程号(PID)对应的长河名.

十二、协程

 1 import time
 2 
 3 """
 4 传统的生产者-消费者模型是一个线程写消息,一个线程取消息,通过锁机制控制队列和等待,但一不小心就可能死锁。
 5 如果改用协程,生产者生产消息后,直接通过yield跳转到消费者开始执行,待消费者执行完毕后,切换回生产者继续生产,效率极高。
 6 """
 7 # 注意到consumer函数是一个generator(生成器):
 8 # 任何包含yield关键字的函数都会自动成为生成器(generator)对象
 9 
10 def consumer():
11     r = ''
12     while True:
13         # 3、consumer通过yield拿到消息,处理,又通过yield把结果传回;
14         #    yield指令具有return关键字的作用。然后函数的堆栈会自动冻结(freeze)在这一行。
15         #    当函数调用者的下一次利用next()或generator.send()或for-in来再次调用该函数时,
16         #    就会从yield代码的下一行开始,继续执行,再返回下一次迭代结果。通过这种方式,迭代器可以实现无限序列和惰性求值。
17         n = yield r
18         if not n:
19             return
20         print('[CONSUMER] ←← Consuming %s...' % n)
21         time.sleep(1)
22         r = '200 OK'
23 def produce(c):
24     # 1、首先调用c.next()启动生成器
25     next(c)
26     n = 0
27     while n < 5:
28         n = n + 1
29         print('[PRODUCER] →→ Producing %s...' % n)
30         # 2、然后,一旦生产了东西,通过c.send(n)切换到consumer执行;
31         cr = c.send(n)
32         # 4、produce拿到consumer处理的结果,继续生产下一条消息;
33         print('[PRODUCER] Consumer return: %s' % cr)
34     # 5、produce决定不生产了,通过c.close()关闭consumer,整个过程结束。
35     c.close()
36 if __name__=='__main__':
37     # 6、整个流程无锁,由一个线程执行,produce和consumer协作完成任务,所以称为“协程”,而非线程的抢占式多任务。
38     c = consumer()
39     produce(c)
40     
41     
42 '''
43 result:
44 
45 [PRODUCER] →→ Producing 1...
46 [CONSUMER] ←← Consuming 1...
47 [PRODUCER] Consumer return: 200 OK
48 [PRODUCER] →→ Producing 2...
49 [CONSUMER] ←← Consuming 2...
50 [PRODUCER] Consumer return: 200 OK
51 [PRODUCER] →→ Producing 3...
52 [CONSUMER] ←← Consuming 3...
53 [PRODUCER] Consumer return: 200 OK
54 [PRODUCER] →→ Producing 4...
55 [CONSUMER] ←← Consuming 4...
56 [PRODUCER] Consumer return: 200 OK
57 [PRODUCER] →→ Producing 5...
58 [CONSUMER] ←← Consuming 5...
59 [PRODUCER] Consumer return: 200 OK
60 '''

 

greenlet:

greenlet机制的主要性思想是:生成器函数或然协程函数中的yield语句挂起函数的实行,直到稍后使用next()或send()操作进行还原甘休。能够行使二个调节器循环在一组生成器函数之间同盟多个职分。greentlet是python中贯彻大家所谓的”Coroutine(协程)”的一个基础库. 

 1 from greenlet import greenlet
 2  
 3 def test1():
 4     print (12)
 5     gr2.switch()
 6     print (34)
 7     gr2.switch()
 8  
 9 def test2():
10     print (56)
11     gr1.switch()
12     print (78)
13  
14 gr1 = greenlet(test1)
15 gr2 = greenlet(test2)
16 gr1.switch()
17 
18 
19 #运行结果:
20 #12
21 #56
22 #34
23 #78

基于greenlet的框架——gevent

gevent模块落成协程:

Python通过yield提供了对协程的宗旨扶助,可是不完全。而第1方的gevent为Python提供了相比完善的协程帮助。

gevent是第一方库,通过greenlet达成协程,其主旨理维是:

当2个greenlet遭逢IO操作时,比方访问网络,就自动切换成其余的greenlet,等到IO操作落成,再在至极的时候切换回来继续施行。由于IO操作尤其耗时,平日使程序处于等候情况,有了gevent为大家自行切换协程,就保障总有greenlet在运营,而不是伺机IO。

是因为切换是在IO操作时自动完结,所以gevent要求修改Python自带的1部分标准库,那一进度在运行时通过monkey
patch落成:

澳门葡京备用网址 129澳门葡京备用网址 130

 1 from gevent import monkey
 2 monkey.patch_all()
 3 import gevent
 4 from urllib import request
 5 import time
 6 
 7 def f(url):
 8     print('GET: %s' % url)
 9     resp = request.urlopen(url)
10     data = resp.read()
11     print('%d bytes received from %s.' % (len(data), url))
12 
13 start=time.time()
14 
15 gevent.joinall([
16         gevent.spawn(f, 'https://itk.org/'),
17         gevent.spawn(f, 'https://www.github.com/'),
18         gevent.spawn(f, 'https://zhihu.com/'),
19 ])
20 
21 print(time.time()-start)
22 
23 
24 
25 #运行结果:
26 #GET: https://itk.org/
27 #GET: https://www.github.com/
28 #GET: https://zhihu.com/
29 #9077 bytes received from https://zhihu.com/.
30 #12323 bytes received from https://itk.org/.
31 #92574 bytes received from https://www.github.com/.
32 #3.7679357528686523

gevent实例

 

 

澳门葡京备用网址 131澳门葡京备用网址 132

 1 from gevent import monkey
 2 monkey.patch_all()
 3 import gevent
 4 from urllib import request
 5 import time
 6 
 7 def f(url):
 8     print('GET: %s' % url)
 9     resp = request.urlopen(url)
10     data = resp.read()
11     print('%d bytes received from %s.' % (len(data), url))
12 
13 start=time.time()
14 
15 # gevent.joinall([
16 #         gevent.spawn(f, 'https://itk.org/'),
17 #         gevent.spawn(f, 'https://www.github.com/'),
18 #         gevent.spawn(f, 'https://zhihu.com/'),
19 # ])
20 
21 f('https://itk.org/')
22 f('https://www.github.com/')
23 f('https://zhihu.com/')
24 
25 print(time.time()-start)
26 
27 
28 
29 #运行结果:
30 #GET: https://itk.org/
31 #12323 bytes received from https://itk.org/.
32 #GET: https://www.github.com/
33 #92572 bytes received from https://www.github.com/.
34 #GET: https://zhihu.com/
35 #8885 bytes received from https://zhihu.com/.
36 #5.089903354644775

比较串行方式的运作功能

 

参考资料:

2.

 

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website