|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 Stubborn 于 2019-3-12 00:48 编辑
B线程篇
在一个进程的内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程
线程通常叫做轻型的进程,线程是共享内存空间的并发执行的多任务,每一个线程都共享一个进程的资源
线程是最小的执行单元,而进程由至少一个线程组成,如何调度进程和线程,完全有系统决定,程序自己不能决定什么时候执行,执行多长时间
线程模块
1,thread模块 低级模块,接近底层
2,threading模块 高级模块对_thread进行了封装
B1===>启动一个线程
- import threading
- def run(a):
- print("子线程(-%s-)启动"%(threading.current_thread().name))
- print("子线程开始干事情啦:",a)
- print("子线程(-%s-)结束" % (threading.current_thread().name))
- if __name__ == '__main__':
- #任何进程默认就会启动一个线程,称为主线程,主线程可以启动新的子线程
- #current_thread()返回当前线程的实例
- print("主线程(-%s-)启动"%(threading.current_thread().name))
- t = threading.Thread(target=run,name="rooThread",args="a")
- #启动线程
- t.start()
- #结束线程
- t.join()
- print("主线程(-%s-)结束" % (threading.current_thread().name))
复制代码
B2===>全局变量在多个线程中共享
多线程和多进程最大的不同在于,多进程中,同一个变量各自有一分拷贝存在每个进程中,互不影响
而多线程中,所有的变量都有所有线程共享。所以任何一个变量都可以被任意一个线程修改,
因此线程之间,共享数据最大的危险在于多个线程同时修改改一个变量,容易吧内容改乱。
如下代码当range大到一定数值,线程同时对数据修改,会产生不可估计的值。结果肯定不会为零
- from threading import Thread
- num = 0
- def run(n):
- global num
- for i in range(10):
- num += n #当线程同时执行到这里,num已经等于9,另外一个线程执行了 9 + 6 此时num=15
- num -= n #这里执行就变成 15 - 6
- if __name__ == '__main__':
- t1 = Thread(target=run,args=(6,))
- t2 = Thread(target=run,args=(9,))
- t1.start()
- t2.start()
- t1.join()
- t2.join()
- print("NUM =",num)
复制代码
B3===>线程锁解决数据混乱
- from threading import Thread,Lock
- #锁对象
- lock = Lock()
- num = 0
- def run(n):
- global num
- for i in range(10000000):
- '''
- # 加上线程锁
- #确保线程锁中,只能有一个线程存在执行
- #阻塞了多线程的并发执行,包含锁的某段代码实际上只能以单线程模式执行,所以效率消耗非常大
- #由于存在多个锁,不同线程持有不同的锁,并试图获取其他的锁,可能造成死锁,导致多个线程挂起(被挡在锁外面,一直等待),只能靠系统强制终止
- lock.acquire()
- try:
- num += n
- num -= n
- finally:
- #释放线程锁
- lock.release()
- '''
- #与上面代码功能相同,with lock ,可以自动上锁,与解锁
- with lock:
- num += n
- num -= n
- if __name__ == '__main__':
- t1 = Thread(target=run,args=(6,))
- t2 = Thread(target=run,args=(9,))
- t1.start()
- t2.start()
- t1.join()
- t2.join()
- print("NUM =",num)
复制代码
B4===>信号量控制线程数量
- import threading,time
- sem = threading.Semaphore(5) #控制线程数量
- def run():
- with sem:
- for i in range(10):
- print("{}--{}".format(threading.current_thread().name,i))
- time.sleep(2)
- if __name__ == '__main__':
- for i in range(5):
- threading.Thread(target=run).start()
复制代码
B5===>等待一定线程数量才能一起执行
- import threading,time
- sem = threading.Barrier(3) #等待3个线程数量一起启动
- def run():
- print("{}--start".format(threading.current_thread().name))
- time.sleep(2)
- sem.wait()
- print("{}--end".format(threading.current_thread().name))
- if __name__ == '__main__':
- for i in range(6):
- threading.Thread(target=run).start()
复制代码
B6===>定时线程
- import threading
- def run():
- print("{}--start".format(threading.current_thread().name))
- #延时执行线程
- t = threading.Timer(5,run)
- t.start()
- t.join()
- print("父线程结束")
复制代码
B7===>线程通讯
- import threading,time
- def frun():
- print("{}--start".format(threading.current_thread().name))
- #事件对象,event没有出发,线程被挂起
- event = threading.Event()
- def run():
- for ui in range(5):
- #阻塞,等待事件的出发
- event.wait()
- #重置
- event.clear()
- print("Stubbron is a good man!%d"%ui)
- t = threading.Thread(target=run).start()
- return event
- e = frun()
- #触发事件
- for i in range(5):
- time.sleep(2)
- e.set()
复制代码
B8===>生产者与消费者
- '''
- 生产数据A ========================== 消费数据A
- 生产数据B 队列 消费数据B
- 生产数据C ===========================消费数据C
- '''
- import threading,time,queue,random
- #生产数据
- def product(id,q):
- while True:
- num = random.randint(0,100)
- q.put(num)
- print("生产数据{}产生{}数据存入队列".format(id,num))
- time.sleep(3)
- #任务完成
- q.task_done()
- #消费数据
- def customer(id,q):
- while True:
- item = q.get()
- if item is None:
- break
- print("消费数据{}消费{}数据弹出入队列".format(id, item))
- time.sleep(2)
- #任务完成
- q.task_done()
- if __name__ == '__main__':
- #数据队列
- q = queue.Queue()
- #启动生产数据
- produc = []
- for i in range(3):
- threading.Thread(target=product,args=(i,q)).start()
- # 消费数据
- for i in range(3):
- threading.Thread(target=customer,args=(i,q)).start()
复制代码
B10===>线程调度
- '''
- 如何让线程1,2轮流执行
- ---------------------------
- 线程1| 0 2 4 6 8
- ---------------------------
- 线程2||1 3 5 7 9
- ---------------------------
- |0 1 2 3 4 5 6 7 8 9
- --------------------------
- '''
- import threading,time
- #线程条件变量
- cond = threading.Condition()
- def arun():
- with cond:
- for i in range(0,10,2):
- print("{}--start{}".format(threading.current_thread().name,i))
- time.sleep(2)
- cond.wait() #等待,收到通知继续
- cond.notify() #通知
- def brun():
- with cond:
- for i in range(1,10,2):
- print("{}--start{}".format(threading.current_thread().name,i))
- time.sleep(2)
- cond.notify() #通知
- cond.wait() #通知完等待
- if __name__ == '__main__':
- threading.Thread(target=arun).start()
- threading.Thread(target=brun).start()
复制代码
B11===>本地线程
- import threading
- #创建一个全局的ThreadLocal对象
- #每个线程有独立的储存空间
- #线程对ThreadLocal对象都可以读写,但是互不影响
- num = 0
- loca = threading.local()
- def run(x,n):
- x = x + n
- x = x - n
- def runc(n):
- loca.x = num
- for i in range(1000000):
- run(loca.x , n)
- print("{}--{}".format(threading.current_thread().name,loca.x))
- if __name__ == '__main__':
- t1 = threading.Thread(target=runc,args=(6,))
- t2 = threading.Thread(target=runc,args=(9,))
- t1.start()
- t2.start()
- t1.join()
- t2.join()
- print("NUM =",num)
- #作用:为每个线程绑定一个数据库链接,http请求,用户信息等
- #这样没一个线程的所有调用到的处理函数话都可以非常方便的访问这些资源
复制代码
额外小作业
下面有两段代码:Server.py client.py 这个可以两个之间类似两个发送信息。但是不能多个链接。试试在里面加入线程,使其服务端可以被多个客户端链接
还可以做界面出来。想想强大,还可以私信给某一个客户端,使用服务端做中转站
Server.py
- #!/usr/bin/env python3.7
- # _*_ coding: utf-8 _*_
- # @Time : 2019/3/11 12:52
- # @Author : Stubbron
- # @Email : 1263270345@qq.com
- #文件 :Server.py
- #IDE :PyCharm
- import socket,threading
- #创建一个socket
- server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
- #绑定IP和端口
- server.bind(("192.168.56.1",8080)) #IP为自己主机IP地址
- #监听
- server.listen(5)
- print('服务器启动成功')
- #等待链接,只能等待一个连接
- clientSocket, clientAddress = server.accept()
- print("{}客户端连接成功".format(clientAddress))
- while True:
- print("{}--{}客户端连接成功".format(str(clientSocket), clientAddress))
- data = clientSocket.recv(1024)
- print("收到数据:",data.decode("utf-8"))
- data = input("输入给服务器发送的数据")
- clientSocket.send("{} Good man".format(data).encode("utf-8"))
复制代码
client.py
- import socket
- client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
- client.connect(("192.168.56.1",8080))
- while True:
- data = input("输入给服务器发送的数据")
- client.send(data.encode("utf-8"))
- info = client.recv(1024)
复制代码
|
|