线程,协程,IO模型

理论:

1.每创造一个进程,默认里面就有一个线程
2.进程是一个资源单位,而进程里面的线程才是CPU上的一个调度单位
3.一个进程里面的多个线程,是共享这个进程里面的资源的
4.线程创建的开销比进程要小,不用申请空间,只要基于现在的进程所在的空间,开一条流水线
就可以,所以创造线程的速度比创造进程的速度快
5.进程之间更多的是竞争关系,因为他们彼此之间是互相隔离的,而同一个进程的线程之间是合作关系

线程与进程的区别
1.同一进程内的线程共享创建它们的进程的地址空间,也就是同一进程内的多个线程共享资源,进程拥有自己的地址空间,也就是说父进程
和子进程是完全独立的地址空间
2.线程可以直接访问进程的数据。在Linux系统下,主进程造一个子进程,子进程会把父进程的状态完整的拷贝一份当作子进程的初始状态,但是当子进程
在运行过程中再产生的数据或者把数据更改了就和父进程无关了
3.同一进程的线程可以相互通信。进程彼此之间内存空间是相互隔离的,若通信需要找一块共享的内存空间,共享意味着竞争,
所以需要加锁处理,那么就需要寻找既是共享的内存空间,而且还自动处理了锁,使用队列。队列就是ipc机制的一种进程之间
通信的方式,与它相类似的还有管道,只不过管道需要自己加锁处理,所以还是使用队列更方便。
线程是没有必要使用ipc机制的,因为默认就是共享同一进程的内存空间,但存在竞争的问题,所以只能加锁,使用线程自己的队列
4.同等资源情况下,能开的线程数量多于开的进程数量,线程开销小,创建速度快,意味着能创建更多线程

开启线程的两种方式

1.

from threading import Thread

def task():
    print(‘is running‘)

if __name__==‘__main__‘:
    t=Thread(target=task,)
    t.start()
    print(‘主‘)

#is running
#主
t.start() 发信号给操作系统,但是是基于当前进程已经有了空间的基础之上直接开线程
就可以了,当开始运行第一行代码的时候,进程就已经产生了,等到运行t.stat()的时候,
进程的空间早就开启了好长时间了,所以start的时候不用申请空间了,直接开一个流水线
就好了,开销小,所以就先看到‘is running‘

from  multiprocessing import Process

def task():
    print(‘is running‘)

if __name__ == ‘__main__‘:
    t=Process(target=task,)
    t.start()
    print(‘主‘)

#主
#is running
开进程的开销大,要拷贝父进程的状态,需要的时间长,在 t.start() 给操作系统发出
申请后,操作系统要申请空间把这个进程造出来,还要再造一个线程,在这段时间内,
print(‘主‘)已经执行了。子进程造出来后就打印 is running

2.

from threading import Thread

class MyThread(Thread):
    def run(self):
        print(‘is running‘)

if __name__ == ‘__main__‘:
    t=MyThread()
    t.start()
    print(‘主‘)

如果要传参数

from threading import Thread

class MyThread(Thread):
    def __init__(self,name):
        super().__init__()
        self.name=name

    def run(self):
        print(‘%s is running‘ % self.name)

if __name__ == ‘__main__‘:
    t=MyThread(‘egon‘)
    t.start()
    print(‘主‘)

线程与进程

from threading import Thread
from multiprocessing import Process
import os 

def task():
    print(‘%s is running‘ % os.getpid())

if __name__==‘__main__‘:
    t1=Thread(target=task,)
    t2=Thread(target=task,)
    t1.start()
    t2.start()
    print(‘主‘,os.getpid())

#1376 is running
#1376 is running
#主 1376
线程和主线程看到的pid都是一样的,因为这多个线程都是在一个进程里面

from threading import Thread
from multiprocessing import Process
import os 

def task():
    print(‘%s is running‘ % os.getpid())

if __name__==‘__main__‘:
    t1=Process(target=task,)
    t2=Process(target=task,)
    t1.start()
    t2.start()
    print(‘主‘,os.getpid())

#主 4136             主进程pid
#5588 is running     子进程pid
#6532 is running     子进程pid

多线程共享同一个进程内的资源

from threading import Thread
from multiprocessing import Process

n=100
def work():
    global n
    n=0

if __name__==‘__main__‘:
    p=Process(target=work,)
    p.start()
    p.join()
    print(‘主‘,n)

#主 100
主进程看n,主进程的n没有被改过
在开子进程的时候,数据会被拷贝到子进程,改全局变量是改的子进程的全局变量,
子进程的n改为0,但是主进程的n仍然是100
子进程与主进程是完全独立的内存空间

from threading import Thread
from multiprocessing import Process

n=100
def work():
    global n
    n=0

if __name__==‘__main__‘:
    t=Thread(target=work,)
    t.start()
    t.join()
    print(‘主‘,n)

# 主 0

线程是共享同一个进程的地址空间,改全局变量的n,这个n就来自进程的n,直接就改掉了

多线程共享同一进程内地址空间练习

from threading import Thread
msg_l=[]
format_l=[]
def talk():
    ‘‘‘用户输入后添加到列表‘‘‘
    while True:
        msg=input(‘>>: ‘).strip()
        msg_l.append(msg)

def format():
    ‘‘‘弹出数据并且改为大写后添加到新列表‘‘‘
    while True:
        if msg_l:
            data=msg_l.pop()
            format_l.append(data.upper())

def save():
    while True:
        if format_l:  # 如果有数据
            data=format_l.pop()   # 数据拿出来后保存到文件中
            with open(‘db.txt‘,‘a‘) as f:
                f.write(‘%s\n‘%data)

#因为中间需要共享数据所以需要多线程

if __name__==‘__main__‘:
    t1=Thread(target=talk,)
    t2=Thread(target=format,)
    t3=Thread(target=save,)

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

所以只要是涉及到共享数据的多个并发任务可以用多线程实现

Thread对象其他相关的属性或方法

from threading import Thread

def talk():
    print(‘is running‘)

if __name__==‘__main__‘:
    t=Thread(target=task,)
    t.start()
    t.join()    # 主进程等待子线程执行完
    print(t.is_alive())   # 判断线程是否存活
    print(‘主‘)

#is running
#False
#主
from threading import Thread

def talk():
    print(‘is running‘)

if __name__==‘__main__‘:
    t=Thread(target=task,)
    t.start()
    print(t.is_alive())
    print(‘主‘)
    print(t.is_alive()) 

#is running
#True
#主
#True
from threading import Thread

def talk():
    print(‘is running‘)

if __name__==‘__main__‘:
    t=Thread(target=task,)
    t.start()
    print(t.is_alive())
    print(t.getName())
    print(‘主‘)
    print(t.is_alive()) 

#is runnning
#False
#Thread-1
#主
#False

所以在没有join方法的情况下,True和False是说不准的,
取决于操作系统什么时候回收它,它才什么时候会死掉

from threading import Thread,activeCount

def talk():
    print(‘is running‘)

if __name__==‘__main__‘:
    t=Thread(target=task,)
    t.start()
    print(‘主‘)
    print(activeCount())

#is running
#主
#2            -----> 活着的线程数,一个主线程,和主线程开启的线程
from threading import Thread,activeCount,enumerate

def talk():
    print(‘is running‘)

if __name__==‘__main__‘:
    t=Thread(target=task,)
    t.start()
    print(‘主‘)
    print(activeCount())
    print(enumerate())    # --->显示当前活跃的线程对象

#is running
#主
#1
#[<_MainThread(MainThread, started 5588)>]
from threading import Thread,activeCount,enumerate
import time

def talk():
    print(‘is running‘)
    time.sleep(2)    # 保证2s内线程死不掉

if __name__==‘__main__‘:
    t=Thread(target=task,)
    t.start()
    print(enumerate())
    print(‘主‘)

#is running
#[<_MainThread(MainThread, started 1060)>, <Thread(Thread-1, start 4496)>]
#主

一个主线程和一个Thread-1线程
#加入一个join方法
from threading import Thread,activeCount,enumerate
import time

def talk():
    print(‘is running‘)
    time.sleep(2)    # 保证2s内线程死不掉

if __name__==‘__main__‘:
    t=Thread(target=task,)
    t.start()
    t.join()
    print(enumerate())
    print(‘主‘)

#is running
#[<_MainThread(MainThread, started 6172)>]
#主

只有主线程
from threading import Thread,activeCount,enumerate,current_thread
import time

def talk():
    print(‘%s is running‘%current_thread().getName())  # 当前的线程对象
    time.sleep(2)   

if __name__==‘__main__‘:
    t=Thread(target=task,)
    t.start()
    t.join()

    print(‘主‘)

#Thread-1 is running

验证开一个进程默认就有一个主线程
from threading import Thread,current_thread
from multiprocessing import Process
import time

print(current_thread())

#<_MainThread(MainThread, started 6192)>

右键一运行就会产生一个进程,进程不是一个执行单位,只是一个资源单位
主进程执行其实是主进程中的主线程在执行,所以谈到执行一定往线程上靠

from threading import Thread,current_thread
from multiprocessing import Process
import time

def task():
    print(‘%s is running‘% current_thread().getName())  # 子进程的Main_Thread
    time.sleep(2)

if __name__==‘__main__‘:
    p=Process(target=task,)  # 这个进程中的主线程开始执行代码了
    p.start()    # 开一个子进程,里面还有一个主线程
    print(current_thread())   # 父进程的主线程

#<_MainThread(MainThread, started 5056)>
#MainThread is running

主线程从执行层面代表了其所在进程的执行过程

from threading import Thread,current_thread
from multiprocessing import Process
import time

def task():
    print(‘%s is running‘% current_thread().getName())
    time.sleep(2)

if __name__==‘__main__‘:
    t1=Thread(target=task,)
    t2=Thread(target=task,)
    t3=Thread(target=task,)
    t1.start()
    t2.start()
    t3.start()
    print(current_thread().getName()) 

#Thread-1 is running
#Thread-2 is running
#Thread-3 is running
#MainThread

在一个进程里面,主线程只有一个,其余的都是它开启的一些线程

守护线程

主线程挂掉,守护线程也会挂掉

#先看守护进程
from multiprocessing import Process
import time

def task():
    print(‘123‘)
    time.sleep(2)
    print(‘123done‘)

if __name__ == ‘__main__‘:
    p=Process(target=task,)
    p.start()
    print(‘主‘)

#主
#123
#123done

主进程即使运行完了也要一直等待子进程运行完毕才结束掉

from multiprocessing import Process
import time

def task():
    print(‘123‘)
    time.sleep(2)
    print(‘123done‘)

if __name__ == ‘__main__‘:
    p=Process(target=task,)
    p.daemon=True
    p.start()
    print(‘主‘)

#主

只要主进程运行完毕守护进程就死掉,那么主怎么算运行完毕,代码运行完了就算完了
‘主‘出来,子进程还没来得及开启就已经被干掉了

from multiprocessing import Process
import time

def task1():
    print(‘123‘)
    time.sleep(1)
    print(‘123done‘)

def task2():
    print(‘456‘)
    time.sleep(10)
    print(‘456done‘)

if __name__ == ‘__main__‘:
    p1=Process(target=task1,)
    p2=Process(target=task2,)
    p1.daemon=True
    p1.start()
    p2.start()
    print(‘主‘)

#主
#456
#456done

10s的话 ‘123‘‘123done‘应该也出来了,为什么没有出来,
因为主进程代码结束就把p1干掉了,还没有来得及开启,
虽然代码运行完毕了,但是还要等待子进程p2运行完毕

如果机器的性能非常高,在p1.start()h和p2.start()的时候就已经
运行起来了,有可能‘123‘就打印在屏幕上了,但1s的时间对于操作系统
已经足够长了,足够可以打印出‘主‘,然后p1就被干掉了

对主进程来说,运行完毕指的是主进程代码运行完毕

对主线程来说,运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕

from threading import Thread
import time

def task1():
    print(‘123‘)
    time.sleep(1)
    print(‘123done‘)

if __name__ == ‘__main__‘:
    t=Thread(target=task1,)
    t.start()
    print(‘主‘)

#123
#主
#123done
from threading import Thread
import time

def task1():
    print(‘123‘)
    time.sleep(1)
    print(‘123done‘)

if __name__ == ‘__main__‘:
    t=Thread(target=task1,)
    t.daemon=True
    t.start()
    print(‘主‘)

#123
#主
from threading import Thread
import time

def task1():
    print(‘123‘)
    time.sleep(1)
    print(‘123done‘)

def task2():
    print(‘456‘)
    time.sleep(1)
    print(‘456done‘)

if __name__ == ‘__main__‘:
    t1=Thread(target=task1,)
    t2=Thread(target=task2,)
    t1.daemon=True
    t1.start()
    t2.start()
    print(‘主‘)

#123
#456
#主
#123done
#456done

进程中除了有主线程,还有其他非守护线程,主线程要等着非守护线程task2结束,要等
10s,但是10s也够task1运行完毕了,所以也会打印‘123done‘

from threading import Thread
import time

def task1():
    print(‘123‘)
    time.sleep(10)
    print(‘123done‘)

def task2():
    print(‘456‘)
    time.sleep(1)
    print(‘456done‘)

if __name__ == ‘__main__‘:
    t1=Thread(target=task1,)
    t2=Thread(target=task2,)
    t1.daemon=True
    t1.start()
    t2.start()
    print(‘主‘)

#123
#456
#主
#456done

线程的互斥锁

 1 from threading import Thread,Lock
 2 import time
 3
 4 n=100
 5 def work():
 6     global n
 7     mutex.acquire()
 8     temp=n
 9     time.sleep(0.1)
10     n=temp-1
11     mutex.release()
12
13 if __name__ == ‘__main__‘:
14     mutex=Lock()
15     l=[]
16     start=time.time()
17     for i in range(100):
18         t=Thread(target=work,)
19         l.append(t)
20         t.start()
21
22     for t in l:
23         t.join()
24     print(‘run time:%s value:%s‘%(time.time()-start,n))

互斥锁与join的区别

from threading import Thread,Lock
import time

n=100
def work():
    global n
    temp=n
    time.sleep(0.1)
    n=temp-1

if __name__ == ‘__main__‘:
    start=time.time()
    for i in range(100):
        t=Thread(target=work,)
        l.append(t)
        t.start()
        t.join()

    print(‘run time:%s value:%s‘%(time.time()-start,n))

死锁与递归锁

#死锁
from threading import Thread,Lock
import time

mutexA=Lock()
mutexB=Lock()

class Mythread(Thread):
    def run(self):
        self.f1()
        self.f2()

    def f1(self):
        mutexA.acquire()
        print(‘抢到了A锁‘%self.name)
        mutexB.acquire()
        print(‘抢到了B锁‘%self.name)
        mutexB.release()
        mutexA.release()

    def f2(self):
        mutexB.acquire()
        print(‘抢到了B锁‘%self.name)
        time.sleep(1)
        mutexA.acquire()
        print(‘抢到了A锁‘%self.name)
        mutexA.release()
        mutexB.release()

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

#Thread-1 抢到了A锁
#Thread-1 抢到了B锁
#Thread-1 抢到了B锁
#Thread-2 抢到了A锁
#递归锁
from threading import Thread,Lock
import time

mutexA=Lock()
mutexB=Lock()

class Mythread(Thread):
    def run(self):
        self.f1()
        self.f2()

    def f1(self):
        mutexA.acquire()
        print(‘抢到了A锁‘%self.name)
        mutexB.acquire()
        print(‘抢到了B锁‘%self.name)
        mutexB.release()
        mutexA.release()

    def f2(self):
        mutexB.acquire()
        print(‘抢到了B锁‘%self.name)
        time.sleep(1)
        mutexA.acquire()
        print(‘抢到了A锁‘%self.name)
        mutexA.release()
        mutexB.release()

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

IO模型介绍

同步,异步指的是提交任务或调用任务的方式

阻塞指的是线程的执行状态

1.等待数据的准备
2.将数据从内核拷贝到进程中

1.阻塞IO
阻塞io服务端
from socket import *
server=socket(AF_INET,SOCK_STREAM)
server.bind((‘127.0.0.1‘,8080))
server.listen(5)

while True:
    conn,addr = server.accept()
    print(addr)
    while True:
        try:
            data=conn.recv(1024)
            if not data:break
            conn.send(data.upper())
        except Exception:
            break
    conn.close()

server.close()
非阻塞IO

服务端
from socket import *
server=socket(AF_INET,SOCK_STREAM)
server.bind((‘127.0.0.1‘,8080))
server.listen(5)
server.setblocking(False)   # 默认为True, 改为False就是非阻塞
import time

conns=[]
del_l=[]
while True:
    try:
        print(conns)
        conn,addr = server.accept()
        conns.append(conn)
    except BlockingIOError:
        for conn in conns:
            try:
                data=conn.recv(1024)
                conn.send(data.upper())
            except BlockingIOError:
                pass
            except ConnectionResetError:
                conn.close()
                del_l.append(conn)
        for conn in del_l:
            conns.remove(conn)
        del_l=[]

客户端

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‘))
    data=client.recv(1024)
    print(data.decode(‘utf-8‘))
IO多路复用(推荐)

实现select IO多路复用模型

服务端

from socket import *
import select
import time
server=socket(AF_INET,SOCK_STREAM)
server.bind((‘127.0.0.1‘,8080))
server.listen(5)
server.setblocking(False)
reads=[server,]

while True:
    rl,_,_=select.select(reads,[],[])
    for obj in rl:
        if obj == server:
            conn,addr=obj,accept()
            reads.append(conn)
        else:
            try:
                data=obj.recv(1024)
                if not data:
                    obj.close()
                    reads.remove(obj)
                    continue
                obj.send(data.upper())
            except Exception:
                obj.close()
                reads.remove(obj)

协程

在单线程下实现并发

1.基于yield实现并发
import time
def consumer():
    while True:
        res=yield

def producer():
    g=consumer()
    next(g)
    for i in range(1000000):
        g.send(i)

start=time.time()
producer()
print(time.time()-start)

没有遇到io就乱切换,只是单纯的切换,反而会降低运行效率
import time
def consumer(res):
    print(‘consumer‘)
    time.sleep(10)

def producer():
    res=[]
    for i in range(1000000):
        res.append(i)
    return res

start=time.time()
res=producer()
consumer(res)
print(time.time()-start)
import time
def consumer():
    while True:
        res=yield
        print(‘consumer‘,res)
        time.sleep(10)

def producer():
    g=consumer()
    next(g)
    for i in range(10000):
        print(‘producer‘,i)
        g.send(i)

start=time.time()
producer()
print(time.timet()-start)

yield只是单纯的切换,跟效率无关

greenlet模块

只是单纯意义上的切换,唯一的好处是切换起来比yield方便,仍然没有解决遇到IO就切换

from greenlet import greenlet
import time

def eat(name):
    print(‘%s eat 1‘% name)
    g2.switch(‘tom‘)    # 暂停然后切到play()
    print(‘%s eat 2‘% name)
    g2.switch()

def play(name):
    print(‘%s play 1‘% name)
    time.sleep(10)  # 睡的时候并没有切换到别的函数,如eat(),而是继续等待
    g1.switch()    # 第一次传参数就可以了。暂停然后切换到eat()剩余的部分
    print(‘%s play 2‘% name)

g1=greenlet(eat)
g2=greenlet(play)

g1.switch(‘tom‘)  # 切到eat()

# tom eat 1
# tom play 1
# tom eat 2
# tom play 2

gevent模块

import gevent

def eat(name):
    print(‘%s eat 1‘ % name)
    gevent.sleep(3)
    print(‘%s eat 2‘ % name)

def play(name):
    print(‘%s play 1‘ % name)
    gevent.sleep(2)
    print(‘%s play 2‘ % name)

g1=gevent.spawn(eat, ‘tom‘)    # spawn() 是异步提交任务,只管提交任务,不管执行没执行
g2=gevent.spawn(play, ‘tom‘)    # 想要看到执行过程,就需要等(join())

gevent.joinall([g1,g2])

# tom eat 1
# tom play 1
# tom play 2   先睡完(2s),所以就是play 2打印
# tom eat 2

这个函数的io是gevent.sleep()模拟的,如果是time.sleep()呢?,time.sleep()是不能被gevent识别的

from gevent import monkey;monkey.patch_all() #把这句代码之下的所有io操作都打上能被gevent识别的io操作的补丁,否则
import gevent                                #在用time.sleep()时,就会串行运行
import time

def eat(name):
    print(‘%s eat 1‘ % name)
    time.sleep(1)
    print(‘%s eat 2‘ % name)

def play(name):
    print(‘%s play 1‘ % name)
    time.sleep(2)
    print(‘%s play 2‘ % name)

g1=gevent.spawn(eat, ‘tom‘)
g2=gevent.spawn(play, ‘tom‘)   

gevent.joinall([g1,g2])

#tom eat 1
#tom play 1
#tom eat 2
#tom play 2

这就是单线程下的并发,也就是协程了,协程是用户程序自己控制调度的,操作系统是看不到的,我们通过gevent模块把io操作
隐藏了起来。协程的切换开销更小。

基于协程实现并发的套接字通信

#客户端
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‘))
#服务端

from socket import *
import gevent

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)

#客户端
from threading import Thread
from socket import *

def client():
    client=socket(AF_INET, SOCK_STREAM)
    client.connect((‘127.0.0.1‘, 8080))

    while True:
        client.send(‘hello‘, encode(‘utf-8‘))
        msg=client.recv(1024)
        print(msg.decode(‘utf-8‘))

if __name__ == ‘__main__‘:
    for i in range(500):
        t=Thread(target=client,)
        t.start()

协程的缺点:
本质上是单线程,无法利用多核,所以如果想把程序最大效率的提升,就应该把
程序的io操作最大限度地降到最低。
协程指的是单个线程,一旦协程出现阻塞,将会阻塞整个线程

进程池和线程池

concurrent.futures模块提供了进程池和线程池,并且提供了更高级别的接口,
为的是异步执行调用

#进程池
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
import os

def work(n):
    print(‘%s is running‘%os.getpid())
    time.sleep(random.randint(1,3))
    return n**2

if __name__ == ‘__main__‘:
    p=ProcessPoolExecutor()  #默认开4个进程
    objs=[]
    for i in range(10):
        obj=p.submit(work, i)
        objs.append(obj)

    p.shutdown()
    for obj in objs:
        print(obj.result())
#线程池

from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
import os
from threading import current_thread

def work(n):
    print(‘%s is running‘%current_thread().getName())
    time.sleep(random.randint(1,3))
    return n**2

if __name__ == ‘__main__‘:
    p=ThreadPoolExecutor()  #默认为cpu的个数*5
    objs=[]
    for i in range(21):
        obj=p.submit(work, i)
        objs.append(obj)

    p.shutdown()
    for obj in objs:
        print(obj.result())

事件Event

from threading import Thread,current_thread,Event
import time
event=Event()

def conn_mysql():
    count=1
    while not event.is_set():
        if count > 3:
            raise ConnectionError(‘连接失败‘)
        print(‘%s 等待第%s次链接mysql‘%(current_thread().getName(),count))
        event.wait(0.5)  #全局变量默认为False,在这里等变为True,超时时间一过就不再等待
        count+=1
    print(‘%s 链接ok‘ % current_thread().getName())

def check_mysql():
    print(‘%s 正在检查mysql状态‘ % current_thread().getName())
    time.sleep(1)
    event.set()  #把全局变量变为True

if __name__ == ‘__main__‘:
    t1 = Thread(target=conn_mysql)
    t2 = Thread(target=conn_mysql)
    check = Thread(target=check_mysql)

    t1.start()
    t2.start()
    check.start()

定时器

from threading import Timer

def hello(n):
    print(‘hello,world‘,n)

t = Timer(3, hello,args=(11,))  # 3s后运行
t.start()

#hello,world 11

 线程queue(了解)

import queue

q=queue.Queue(3)  #模拟对列,先进先出

q.put(1)
q.put(2)
q.put(3)

print(q.get())
print(q.get())
print(q.get())

#1
#2
#3
import queue

q=queue.LifoQueue(3)   # 模拟堆栈,后进先出

q.put(1)
q.put(2)
q.put(3)

print(q.get())
print(q.get())
print(q.get())

#3
#2
#1
import queue

q=queue.PriorityQueue(3)   #数字越小,优先级越高

q.put((10, ‘data1‘))   # (优先级,数据)
q.put((11, ‘data2‘))
q.put((9, ‘data3‘)) 

print(q.get())
print(q.get())
print(q.get())

#(9, ‘data3‘)
#(10, ‘data1‘)
#(11, ‘data2‘)
时间: 2024-10-12 22:26:18

线程,协程,IO模型的相关文章

python_day10 多线程 协程 IO模型

多线程协程IO模型 多线程 #线程的PID与主进程PID一致 from threading import Thread from multiprocessing import Process import os def task(): print('%s is running' %os.getpid()) if __name__ == '__main__': t1=Thread(target=task,) t2=Thread(target=task,) # t1=Process(target=t

# 进程/线程/协程 # IO:同步/异步/阻塞/非阻塞 # greenlet gevent # 事件驱动与异步IO # Select\Poll\Epoll异步IO 以及selectors模块 # Python队列/RabbitMQ队列

1 # 进程/线程/协程 2 # IO:同步/异步/阻塞/非阻塞 3 # greenlet gevent 4 # 事件驱动与异步IO 5 # Select\Poll\Epoll异步IO 以及selectors模块 6 # Python队列/RabbitMQ队列 7 8 ############################################################################################## 9 1.什么是进程?进程和程序之间有什么

协程/IO多路复用

一.协程: 概念:是一个比线程更加轻量级的单位,是组成线程的各个函数 为什么要有协程: 想要在单线程内实现并发的效果.但因为Cpython有GIL锁,限制了在同一时间点,CPU只能执行一个线程,所以想要在执行一个线程的期间,充分利用cpu的性能,所以才有了想在单线程内实现并发的效果 cpu 为什么要切换: 1.因为某个程序阻塞 2.因为某个程序用完了时间片 很明显,解决1 这个问题才能提高效率 所以想要实现单线程的并发,就要解决在单线程中,多个任务函数中,某个任务函数遇见IO操作,马上自动切换到

Http协议和IO模型

HTTP 协议和IO模型 一:HTTP协议 http协议:HyperText Transfer Procotol超文本传输协议,http协议是无状态的,监听在80端口,TCP协议上.HTTP协议的特点有以下几点: 1.支持客户/服务器模式.2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径.请求方法常用的有GET.HEAD.POST.每种方法规定了客户与服务器联系的类型不同.由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快.3.灵活:HTTP允许传输任意类型的数据

初识进程 线程 协程(三):协程

协程:(又称微线程,也是交替运行) 进程-->线程-->协程 协程就是充分利用cpu给该线程的时间,多个协程只使用一个线程,某个任务遇到阻塞,执行下一个任务.如果一个线程只执行一个任务,比较容易进入阻塞队列,如果这条线程永远在工作(协程:一个线程执行多个任务),永远不会进入阻塞队列. 适用场景:    当程序中存在大量不需要CPU的操作时(IO) 特点: 每次都能从上次暂停的位置继续执行 三种实现方式: 1.yield(生成器) 生成器:一边计算一边循环的机制 def a(): ......

C后端设计开发 - 第3章-气功-原子锁线程协程

正文 第3章-气功-原子锁线程协程 后记 如果有错误, 欢迎指正. 有好的补充, 和疑问欢迎交流, 一块提高. 在此谢谢大家了. 童话镇 - http://music.163.com/#/m/song?id=413829859&userid=16529894

进程线程协程那些事儿

一.进程与线程 1.进程 我们电脑的应用程序,都是进程,假设我们用的电脑是单核的,cpu同时只能执行一个进程.当程序出于I/O阻塞的时候,CPU如果和程序一起等待,那就太浪费了,cpu会去执行其他的程序,此时就涉及到切换,切换前要保存上一个程序运行的状态,才能恢复,所以就需要有个东西来记录这个东西,就可以引出进程的概念了. 进程就是一个程序在一个数据集上的一次动态执行过程.进程由程序,数据集,进程控制块三部分组成.程序用来描述进程哪些功能以及如何完成:数据集是程序执行过程中所使用的资源:进程控制

10 线程 协程 socketserver 基于udp的socketserver

线程进程 操作系统的作用: 1.把硬件丑陋复杂的接口隐藏起来,为应用程序提供良好接口 2.管理,调用进程,并且把进程之间对硬件的竞争变得有序化 多道技术: 1.产生背景:为了实现单cpu下的并发效果 2.分为两部分: 1:空间上的复用(必须实现硬件层面的隔离) 2:时间上的复用(复用cpu的时间片) 什么切换? 1:正在执行的任务遇到的阻塞 2:正在执行的任务运行时间过长 进程:正在运行的一个过程/一个任务,由操作系统负责调用,然后由cpu负责执行程序:就是程序员写的代码并发:伪并行,单核+多道

python-多线程+协程

GIL锁的存在,使python实现不了通过多核来完成多线程并行,如果想让python利用多核,只能通过开多进程来实现.所以python适合执行计算密集型任务. 资源抢占式:线程.进程 协程:协作式---->即非抢占式程序,关键词:yield生成器,主要解决的也是IO操作,但不能利用多核(没有多进程的情况下) 多进程+协程:解决进程并发 重温yield生成器: def f(): print("ok") s=yield 6 print(s) print("ok2"

python的进程/线程/协程

1.python的多线程 多线程就是在同一时刻执行多个不同的程序,然而python中的多线程并不能真正的实现并行,这是由于cpython解释器中的GIL(全局解释器锁)捣的鬼,这把锁保证了同一时刻只有一个线程被执行. 多线程的特点: 线程比进程更轻量级,创建一个线程要比创建一个进程快10-100倍. 线程共享全局变量. 由于GIL的原因,当一个线程遇到IO操作时,会切换到另一个线程,所以线程适合IO密集型操作. 在多核cpu系统中,最大限度的利用多核,可以开启多个线程,开销比进程小的多,但是这并