您的位置:首页 > 编程语言 > Python开发

Python学习笔记_Day018

2018-03-21 21:06 106 查看

今天结束了多线程与多进程的学习,开始进入网络编程的学习

一、多进程与多线程

1. 计算机行业遵循的三大定律

摩尔定律 - 每隔18月,硬件性能翻倍

安迪比尔定律 -

反摩尔定律 -

ps:貌似这个和多进程多线程没啥关系,不过还是可以了解了解

2.如果多个任务之间没有任何的关联(独立子任务)而且希望利用cpu的多核特性,那么我们推荐使用多进程

import time
import random
from multiprocessing import Process

# 如果多个任务之间没有任何的关联(独立子任务)而且希望利用cpu的多核特性
# 那么我们推荐使用多进程
# Information Technology
# 摩尔定律 - 每隔18月,硬件性能翻倍
# 安迪比尔定律 -
# 反摩尔定律 -
def download(filename):

print('开始下载%s...' % filename)
delay = random.randint(5, 15)
time.sleep(delay)
print('%s下载完成, 用时%d秒' % (filename, delay))

def main():
start = time.time()
p1 = Process(target=download, args=('Python从入门到住院.pdf',))
p1.start()
p2 = Process(target=download, args=('Pekin Hot.avi',))
p2.start()
p1.join()  # 等待进程结束
p2.join()
end = time.time()
print('总共耗费了%f秒' % (end - start))
"""
start = time.time()
download('Python从入门到住院.pdf')
download('Pekin Hot.avi')
end = time.time()
print('总共耗费了%f秒' % (end - start))
"""

if __name__ == '__main__':
main()
比如以上代码,需要进行的两个操作,由于无关联,完全可以采取多进程的操作

3.通过面向对象的方式来写多进程或多线程

from threading import Thread
from random import *
import time

class Download(Thread):
def __init__(self, filename):
super().__init__()
self._filename = filename

# 钩子函数(hook) / 回调函数(callback)
def run(self):
print('开始下载%s...' % self._filename)
delay = randint(5, 15)
time.sleep(delay)
print('%s下载完成, 用时%d秒' % (self._filename, delay))

def main():
start = time.time()
d1 = Download('东京热.rmvb')
d2 = Download('加勒比.avi')
d1.start()
d2.start()
d1.j
f3d2
oin()
d2.join()
end = time.time()
print('总共耗费了%f秒' % (end - start))

if __name__ == '__main__':
main()
在以上代码中,可以很容易发现,其实我们并没有调用Download类中的run函数,但是在结果中,run函数却被自动调用了,这是因为run()函数是一个钩子函数,也叫作回调函数,在类中的作用和魔法函数很像,但是run的调用前提是必须让进程或者线程开始

4.当多个线程同时访问一个资源的时候 就有肯能因为竞争资源导致资源的状态错误被多个线程访问的资源我们通常称之为临界资源对临界资源的访问需要加上保护

import time
from threading import Thread, Lock

class Account(object):
def __init__(self):
self._balance = 0
self._lock = Lock()

@property
def balance(self):
return self._balance

def deposit(self, money):
# 当多个线程同时访问一个资源的时候 就有肯能因为竞争资源导致资源的状态错误
# 被多个线程访问的资源我们通常称之为临界资源 对临界资源的访问需要加上保护
if money > 0:
self._lock.acquire()  # 放锁
try:
new_balance = self._balance + money
time.sleep(0.01)
self._balance = new_balance
finally:
self._lock.release()  # 释放锁

class AddMoneyThread(Thread):
def __init__(self, account, money):
super().__init__()
self._account = account
self._money = money

def run(self):
self._account.deposit(self._money)

def main():
account = Account()
tlist = []
for i in range(100):
t = AddMoneyThread(account, 1)
tlist.append(t)
t.start()
for t in tlist:
t.join()
print('账户余额:%d元' % account.balance)

if __name__ == '__main__':
main()
但是同过上面的代码,可以很容易看出一个问题,就是,当加上所之后,程序的运行效率大大下降,所以如果不是真的必须要加上锁,最好别用

二、socket,client,服务端与客户端的编写

1.最简单的启服务器的方法

from socket import socket

def main():
server = socket()  # 新建立一个套接字对象
server.bind('127.0.0.1', 6789) # 绑定ip地址(网络上的主机的身份标识)和端口(用来区分不同服务的ip地址的扩展)
server.listen(512) # 监听
print('服务器已经启动!正在监听...')
while True:

client, addr = server.accept()  # 接收客户端信息
print(addr, '连接成功')
通过accept方法接收客户端的连接,而accept方法是一个阻塞式方法 如果没有客户端连上,那么accept方法会让代码阻塞 直到有客户端连接成功才返回accept方法返回一个元组,元组中的第一个值是代表客户端的对象元组中的第二个值又是一个元组, 其中有客户端的IP地址和客户端的端口运行上面的代码,打开cmd命令窗口, 输入telnet 127.0.0.1 6789 就可以检查是否连接上了服务器

三、练习

案例一、通过多线程的方法,使用json下载图片(小福利)

# URL - Uniform Resource Locator
# https://api.tianapi.com/meinv/?key=ea6c4700539ba230113dcdc0a14b7432 import requests
import json
from threading import Thread
import time

class Filename(Thread):
def __init__(self, p, i):
super().__init__()
self._p = p
self._i = i

def run(self):
print('第%d张图片开始下载' % self._i)
resp = requests.get(self._p)
filename = self._p[self._p.rfind('/') + 1:]
with open(filename, 'wb') as fs:
fs.write(resp.content)
# time.sleep(0.01)
print('第%d张图片下载完成' % self._i)

def main():

# request / response
resp = requests.get('https://api.tianapi.com/meinv/?key=ea6c4700539ba230113dcdc0a14b7432&num=50')
mydict = json.loads(resp.text)
print(mydict)
picture = []
for tempdict in mydict['newslist']:
pic_url = tempdict['picUrl']
picture.append(pic_url)
# start = time.time()
for i in range(len(picture)):
Filename(picture[i], i+1).start()

if __name__ == '__main__':
main()
可以和容易看出来,使用了线程之后,速度真的快到飞起!

案例二、实现不同机器客户端与服务端的连接

服务端:
import socket
from threading import Thread

def main():
class SocketsRecv(Thread):
def __init__(self):
super().__init__()

def run(self):
while True:
text = clients.recv(512)
print('客户端发来的消息:' + text.decode('utf-8'))

class SocketSend(Thread):
def __init__(self):
super().__init__()

def run(self):
while True:
str1 = input()
clients.send(str1.encode('utf-8'))
print('您向客户端发出了信息!')

# 创建一个套接字
server = socket.socket()
server.bind(('10.7.189.89', 6789))
# 监听
server.listen(512)
print('服务器已启动!正在监听...')
while True:
clients, addr = server.accept()  # 接收客户端信息
print(addr, '连接成功!')
try:
SocketSend().start()
SocketsRecv().start()
except ConnectionResetError:
print('客户端断开连接!')

if __name__ == '__main__':
main()
客户端:
from socket import socket
from threading import Thread

def main():
class ClientSend(Thread):
def run(self):
while True:
data = client.recv(512)
#print(type(data))
print('服务端的消息:' + data.decode('utf-8'))

class ClientRecv(Thread):
def run(self):
while True:
text = input()
client.send(text.encode('utf-8'))
print('您向服务端发出信息!')

client = socket()
client.connect(('10.7.189.103', 1202))
ClientSend().start()
ClientRecv().start()

if __name__ == '__main__':
main()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: