-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch.xml
More file actions
92 lines (92 loc) · 56.6 KB
/
search.xml
File metadata and controls
92 lines (92 loc) · 56.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title><![CDATA[CrawlSpider X Splash]]></title>
<url>%2Fcrawlspider-x-splash%2F</url>
<content type="text"><![CDATA[CrawlSpider和Splash的整合 CrawlSpider是Scrapy的CrawlSpider Splash是Splash和Scrapy-Splash插件 前言 由于官方文档只是给出简单使用示例 当与CrawlSpider整合的时候只能自己看源码了 在不破坏框架结构和调用流程的情况下 在其最边缘整合是再好不过的了 如果用scrapy-redis时 DUPEFILTER_CLASS配置冲突建议用scrapy-redis的就行 源码解析 以下为crawl源码 原来只想贴解析的部分 然后发现代码挺少 索性就全贴上来了 源码路径 scrapy/spiders/crawl.py 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100import copyimport sixfrom scrapy.http import Request, HtmlResponsefrom scrapy.utils.spider import iterate_spider_outputfrom scrapy.spiders import Spiderdef identity(x): return xclass Rule(object): def __init__(self, link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=identity): self.link_extractor = link_extractor self.callback = callback self.cb_kwargs = cb_kwargs or {} self.process_links = process_links self.process_request = process_request if follow is None: self.follow = False if callback else True else: self.follow = followclass CrawlSpider(Spider): rules = () def __init__(self, *a, **kw): super(CrawlSpider, self).__init__(*a, **kw) self._compile_rules() def parse(self, response): return self._parse_response(response, self.parse_start_url, cb_kwargs={}, follow=True) def parse_start_url(self, response): return [] def process_results(self, response, results): return results def _build_request(self, rule, link): r = Request(url=link.url, callback=self._response_downloaded) r.meta.update(rule=rule, link_text=link.text) return r def _requests_to_follow(self, response): if not isinstance(response, HtmlResponse): return seen = set() for n, rule in enumerate(self._rules): links = [lnk for lnk in rule.link_extractor.extract_links(response) if lnk not in seen] if links and rule.process_links: links = rule.process_links(links) for link in links: seen.add(link) r = self._build_request(n, link) yield rule.process_request(r) def _response_downloaded(self, response): rule = self._rules[response.meta['rule']] return self._parse_response(response, rule.callback, rule.cb_kwargs, rule.follow) def _parse_response(self, response, callback, cb_kwargs, follow=True): if callback: cb_res = callback(response, **cb_kwargs) or () cb_res = self.process_results(response, cb_res) for requests_or_item in iterate_spider_output(cb_res): yield requests_or_item if follow and self._follow_links: for request_or_item in self._requests_to_follow(response): yield request_or_item def _compile_rules(self): def get_method(method): if callable(method): return method elif isinstance(method, six.string_types): return getattr(self, method, None) self._rules = [copy.copy(r) for r in self.rules] for rule in self._rules: rule.callback = get_method(rule.callback) rule.process_links = get_method(rule.process_links) rule.process_request = get_method(rule.process_request) @classmethod def from_crawler(cls, crawler, *args, **kwargs): spider = super(CrawlSpider, cls).from_crawler(crawler, *args, **kwargs) spider._follow_links = crawler.settings.getbool( 'CRAWLSPIDER_FOLLOW_LINKS', True) return spider def set_crawler(self, crawler): super(CrawlSpider, self).set_crawler(crawler) self._follow_links = crawler.settings.getbool('CRAWLSPIDER_FOLLOW_LINKS', True) 尝试重写过make_requests_from_url和_requests_to_follow 发现都有问题不解析或者不跟踪 然后发现Rule有个process_request参数 一时兴奋 于是自己写了个方法 发现还是没什么用 最后看了看源码发现最后生成器yield返回的是这样的: 12r = self._build_request(n, link)yield rule.process_request(r) 退一步 用的的_build_request方法: 1234def _build_request(self, rule, link): r = Request(url=link.url, callback=self._response_downloaded) r.meta.update(rule=rule, link_text=link.text) return r 用的是scrapy原生的Request 并将rule、link的url和text以及_response_downloaded作为参数传递并返回 其中_response_downloaded方法: 123def _response_downloaded(self, response): rule = self._rules[response.meta['rule']] return self._parse_response(response, rule.callback, rule.cb_kwargs, rule.follow) 包含了rule.callback 也就是写Rule时的callback参数 就保证了下载器下载后能够回调解析 重写 综上所述 仅仅是写个方法给process_request是不够的 最终还是用的原生的Request 所以需要重写_build_request方法 替换掉原生的Request 即: 1234def _build_request(self, rule, link): r = SplashRequest(url=link.url, callback=self._response_downloaded) r.meta.update(rule=rule, link_text=link.text) return r 大功告成 这是最简单的 Splash 禁止下载图片 scrapy-splash并没有直接给出禁止下载图片的api 但是splash已经给出 Spalsh HTTP API 其中render.html接口有个参数 images : integer : optional Whether to download images. Possible values are 1 (download images) and 0 (don’t download images). Default is 1. Note that cached images may be displayed even if this parameter is 0. You can > also use Request Filters to strip unwanted contents based on URL. 在使用SplashRequest传入相关参数即可: 1SplashRequest(args={"images":0}) 下边有一条Note就自己研究吧 Splash Scripts Reference 第二个方法就是写lua脚本 splash.images_enabled Enable/disable images. 即: 123456script = """ function main(splash,args) splash.images_enabled = false end """SplashRequest(endpoint='execute',args={"lua_source":script}) 例子为了保证简单明了 只填写了基本的参数 其他如 url 等参数和return splash:html()等脚本 必要的需自己写上 Splash 设置 UA 同样scrapy-splash并没有直接给出 但设置User-Agent发方法很多 splash:set_user_agent、 splash:set_custom_headers、splash:go在lua脚本中都可以设置 以下是官方文档的例子就直接拿过来了 稍稍整理了一下 splash:set_user_agent splash:set_user_agent Overwrite the User-Agent header for all further requests. Signature: splash:set_user_agent(value) Parameters: value - string, a value of User-Agent HTTP header. Returns: nil. Async: no. 1splash:set_user_agent("reki") splash:set_custom_headers splash:set_custom_headers Set custom HTTP headers to send with each request. Signature: splash:set_custom_headers(headers) Parameters: headers - a Lua table with HTTP headers. Returns: nil. Async: no. Headers are merged with WebKit default headers, overwriting WebKit values in case of conflicts. 123splash:set_custom_headers({ ["User-Agent"] = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:61.0) Gecko/20100101 Firefox/61.0",}) splash:go splash:go Go to an URL. This is similar to entering an URL in a browser address bar, pressing Enter and waiting until page loads. Signature: ok, reason = splash:go{url, baseurl=nil, headers=nil, http_method=“GET”, body=nil, formdata=nil} Parameters: -headers - a Lua table with HTTP headers to add/replace in the initial request. Returns: ok, reason pair. If ok is nil then error happened during page load; reason provides an information about error type. Async: yes, unless the navigation is locked. headers argument allows to add or replace default HTTP headers for the initial request. To set custom headers for all further requests (including requests to related resources) use splash:set_custom_headers or splash:on_request. User-Agent header is special: once used, it is kept for further requests. This is an implementation detail and it could change in future releases; to set User-Agent header it is recommended to use splash:set_user_agent method. 123splash:go{"https://reki.me", headers={ ["User-Agent"] = "Yohane",}}) 参考 scrapy splash scrapy-plash]]></content>
<categories>
<category>手记</category>
</categories>
<tags>
<tag>scrapy</tag>
<tag>splash</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Python3进阶笔记]]></title>
<url>%2Fadvance-python%2F</url>
<content type="text"><![CDATA[Python进阶笔记 内容以缩进形式分层 有些知识点点到为止 python中一切皆对象 python中一切皆对象 可赋值给一个变量 可以添加到集合对象中 可以作为参数传递给函数 可以当做函数的返回值 type object class type->class->obj object是最顶层基类 type也是一个类 同时type也是一个对象 type用于实例一切对象 type()函数用于查看实例由哪一对象生成 .__bases__属性用于查看对象上级继承的是哪一对象 身份 也就是内存地址 用id()函数访问 类型 数据类型 值 赋值 None类型(全局只有一个) 即内存地址相同 数值类型 int float complex bool 迭代类型 序列类型 list bytes byte array memoryview range tuple str array 映射类型 dict 集合类型 set frozenset 上下文管理类型 with语句 其他 模块类型 class和实例 函数类型 方法类型 object对象 type类型 ellipsis类型 notimplemented类对象 魔法函数 魔法函数定义 类中以双下划线开头和结尾的函数 是python内置的 魔法函数影响python语法 python语法实际调用魔法函数 魔法函数 非数学运算 字符串表示 repr 在debug模式调用 输出对象 str 重写字符串 内置函数print()默认调用内置函数str() 数学运算 深入类和对象 鸭子类型和多态 当看到一只鸟走起来像鸭子 游泳起来像鸭子 叫起来像鸭子 那么这只鸟就可以被称为鸭子 方法相关 某个类有某个指定方法 那么就被称为某类型 因为python动态语言的关系 无法从类的类型来判断并实现多态 所以使用鸭子类型来实现多态 抽象基类(abc模块) hasattr(obj,”fun”) 判断某个对象中是否有某个方法 isinstance(obj,otherobj) 通过继承链 判断某个类是否属于某个类 抽象基类的使用 import abc包 类继承 mataclass=abc.ABCMeta 用@abc.abstractmathod装饰器装饰方法 isinstance和type type()判断对象id isinstance() 判断继承继承链 类变量和实例变量 self参数 传递的是类实例 实例变量和类变量是独立的 在实例中修改类变量并不会改变类的类变量 一个类的不同实例会共用同一个实例类变量 类属性和实例属性以及查找顺序 MRO算法 DFS算法 继承关系有菱形时 存在无法达到重写方法的效果 BFS算法 继承关系为Y形时 当出现继承方法重名时 优先继承的类的方法不能优先使用 C3算法(python2.3之后) 使用__mro__属性查看类的查找顺序 静态方法 类方法以及对象方法及参数 方法前由 def 关键字修饰 静态方法用@staticmethod完成初始化 通常在不返回类的情景下使用 没有实例参数self 类方法用@classmethod完成初始化 通常在返回类的情景下使用 第一个参数传递的是类本身 通常写成cls 实例方法 第一个参数传递的是实例本身 通常写为 self 数据封装和私有属性 在对象变量或者对象方法前加双下划线 如 __method 或 __var python自动更名为 _class__method 或者 _class__var 的形式达到隐藏的效果 但仍然可以通过更名后的形式访问 python对象的自省机制 通过__dict__查询属性 会列出部分属性和值 可以通过该属性 以字典是形式访问、添加属性或者修改值 通过dir()方法 只列出对象中的所有属性 super真的是调用父类吗? super执行顺序 调用的是MRO顺序的下一个类的构造函数 mixing继承模式 mixing类功能单一 不和基类关联 可以和任意基类关联 基类可以不和mixin关联就鞥初始化成功 在mixin中不要使用super方法 python中的with语句 上下文管理器协议 实现两个魔法函数 enter() 在with语句中 进入时调用 exit() 在with语句中 结束时调用 with…as…语句 with后的语句(通常实例一个对象)执行后调用__enter__()魔法函数 并返回值 enter()魔法函数执行后的返回值赋值给as后的变量 as后的变量可以在下边的代码块中调用 语句块执行完后调用 exit() 魔法函数 with语句捕获到异常则直接执行__exit__() 魔法函数 contextlib简化上下文管理器 contextlib的使用 import context lib 包 使用@contextlib.contextmanager装饰方法 配合yield使用 yield前的代码块相当于__enter__()魔法函数中的代码块 yield返回一个值 yield后的代码块相当于__exit__() 魔法函数中的代码块 自定义序列类 序列类型的分类 容器序列 (可存放任意类型的容器 ) list tuple deque 扁平序列(指定数据类型) str bytes byte array array.array 可变序列 list deque byte array array 不可变序列 emspstr tuple bytes python中序列类型的abc继承关系 在from collection import abc (容器相关的抽象基类)中 Sequence(不可变序列) 继承Reversible 和 Collection Collection继承Sized Iterable和Container Sized 实现 len 方法 计算长度 Iterable 实现__iter__ 方法 迭代器 用于for循环 Container 实现 contains 方法 用于使用IN 判断数据是否存在 MutableSequence(可变序列) 必须实现__new__ init getitem setitem delitem len insert() 方法 list中extend方法区别 +运算 只能相加相同的序列类型 返回一个新的实例 也就是说id()不同 +=就地加 实际调用MutableSequence.iadd(self,values)方法 iadd 又调用 self.extend(values) 方法 self.extend(values) 通过for循环迭代出每个元素 然后使用self.append()方法追加每个元素 也就是说可以相加不同序列类型 对原来的实例相加 也就是说id()相同 实现可切片的对象(会返回一个新的列表) 可以做取值 赋值 删除操作 [start : end : step] start 表示切片开始位置 默认为0 end 表示切片截止位置 默认为列表长度 step 表示步长 默认为1 切片需实现的__getitem__(self,item)方法 如果以切片访问 item为slice 即切片对象 如果以索引访问 item为int 即索引位置 bisect维护已排序序列 import bisect 导入bisect包 用来处理已排序的序列 bisect模块 insort方法用于插入默认为insort_right bisect方法用于查找(使用二分查找) 默认为bisect_right 还有insort_left和bisect_left方法 即当遇到相同元素时 插入以有相同元素的左边 什么时候我们不该使用列表 array和list的一个重要的区别 array只能存放指定的数据类型 其效率高 列表推导式、生成器表达式、字典推导式 列表推导式(列表推导式性能高于列表操作) [ for in if ] 返回的是一个列表 生成器表达式 ( for in if ) 注:返回的是 generator 生成器类 字典推导式 { key:value for in if } 注: 推导式中的key和value是通常的命名 是不固定的 集合推导式 { one_value for in if } 只要返回一个值即可生成集合 深入python的set和dict dict的abc的继承关系 from collection.abc import Mapping dict属于mapping类型 即继承了mapping dict的常用方法 clear() 删除字典内所有元素 copy() 浅拷贝 指向同一地址 拷贝后的操作会影响被拷贝的数据 深拷贝需要import copy fromkeys() 将可迭代是对象转成dict的keys get() 避免在没有对应元素时抛出异常 items() 拆包key和value setdefault(key, default=None) 和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default update() 合并或添加 即更新原来的dict #猜想 会把迭代中的奇数位元素作为key 偶数位做为value dict的子类 不建议继承list和dict等内置的类型 由于底层使用c语言实现 所以一些操作不会调用覆盖后的方法 如果要继承建议使用 from collections import UserDict 模块 完全有python语言编写 from collections import defaultdict 其中的__missing__函数 作用:在找不到元素时 设置默认值 set和fronzenset set(集合可变) fronzenset(不可变的集合)无序的 不重复 set可以通过add方法添加元素 fronzenset不能 set 的方法 add update 可将两个set合并为一个set difference 返回两个集合的差集 #集合运算 | 并集 & 交集 - 差集 运算符实际是调用魔法函数 issubset 判断是否存在交集 dict和set的实现原理 一些结论 dict查找的性能远远大于list 在list中随着list数据的增大 查找时间会增大 在dict中查找元素的时间 不会随着dict的增大而增大 dict的key或者set的值 都 dict原理(与java中的Map相似) 对key做哈希运算 然后做与运算作为偏移量 如果发生冲突则解决冲突 所以查找时间复杂度为O(1) 1.dict的key或者set的值 都是必须是可以hash的 不可变对象 都是可以hash的 如str fronzenset tuple 可自己实现类的__hash__ 2.dict的内存开销大 但是查询的速度快 自定义的对象或者python内部的对象都是用dict包装的 3.dict的存储顺序和元素添加顺序有关 和内部的hash表偏移有关 #这就是为什么set在更新数据后print出来的数据位置无序且可能会改变原来数据的位置的原因 4.添加数据有可能改变已有数据的顺序 对象引用、可变性和垃圾回收 python中的变量是什么 python和java中的变量本质不一样 python的变量实质上是一个指针 int str 变量可以看做一个便利贴 可以通过is运算符或者id()函数判断是否是同一变量 ==和is的区别 ==判断的是内容是否相等 调用的是__eq__魔法函数 #类似java中的Object.equals is判断的是指针所指的内存地址是否相同 也就是变量id()是否相同 因为python中的intern机制 有时候int str类型内容相同 id也相同 #相当于java中String.intern方法 del语句和垃圾回收 python中垃圾回收的算法是采用 引用计数 引用计数 当一个变量指向一个地址是 那么引用计数器+1 del一个变量时 该地址的引用计数器-1 当引用计数为0时 资源被回收 del语句实际调用__del__魔法函数 一个经典的参数错误 传递的参数尽量为不可变的 #引用传递 参数传递 元类编程 property动态属性 @property装饰器 修饰方法后 可以通过 . 的方式访问 变得与访问属性的方式相同 被修饰方法看作一个属性 该属性的值可以自定义逻辑返回 @xxx.setter 装饰器 xxx为被@property装饰器修饰的方法 同理 用来动态设置动态属性 getattr __getattribute__魔法函数 __getattr__在查找不到属性的时候调用 getattribute__所有属性访问的入口 该魔法函数会调用__getattr 属性描述符和属性查找过程 属性描述符 实现__get__ set delete 任何一个魔法方法 就可以将一个类变成属性描述符 实现了__get__ 和 set 称为数据属性描述符 只实现了__get__ 称为非数据属性描述符 使用:在一个类中将属性描述符实例赋值给类变量 属性查找过程 getattr()方法用于访问实例的变量 #如项目里mogodb_client访问collection的三种方法 1.mongodb_client.r20.dmmr18 2.mongodb_client[r20][dmmr18] 3.getattr(self.mongodb_client[“r20”],“dmmr18”) new 和 init 的区别 new 是用来控制对象的生成过程 ,在对象生成之前 init 是用来完善对象的 如果new方法不返回对象 则不会调用init函数 new(cls, *args, kwargs) 如果指定参数名赋值 则赋值给kwargs 类型为 dict 如果没有指定参数名赋值 则赋值给 *args 类型为 tuple cls 为对象 需return super.()new(cls) 才会调回 init 函数 init(self) 在new 之后被调用 自定义元类 元类是创建类的类 type(object_or_name, bases, dict) 第一个参数为类名 传入str类型 第二个参数为 继承基类 当不继承时需要传入一个空tuple () 第三个参数为 自定义属性和方法 dict类型 key为属性名或函数名 value为属性值或自定义的函数 metaclass 类属性 作用:如 继承抽象基类时做函数重写的检查 指定一个类 通过重写__new__函数来自定义创建类对象和实例的过程 元类需要继承type类 需 return super.()new(cos, *args, **kwargs) *args 和 **kwargs 也需要完整的传递进来 通过元类实现ORM 迭代器和生成器 python中的迭代协议 迭代器是什么? 迭代器是访问集合内元素的一种方式 一般用来遍历数据 迭代器和以下标的访问方式不一样 迭代器是不能返回的 迭代器提供了一种惰性方式数据的方式 list不是一个迭代器 但是可迭代 for语句 自动使用 iter() 内置方法将list变成一个迭代器 for语句才可迭代 from collection.abc import Iterable 可迭代 实现__iter__抽象函数 Iterator 迭代器 实现__next__抽象函数 什么是迭代器和可迭代对象 迭代器与迭代对象逻辑实现要分离 迭代器 继承 from collection.abc import Iterator #java中是继承 implements Iterator 接口 实现 next__魔法函数 维护下一个元素的位置 #java中重写 next() 方法 如没有下一个元素则 raise StopIterator 异常 结束迭代 #java中重写 hasNext() 方法 判断是否还有下一个元素 可迭代对象 实现__iter 魔法函数 return 一个迭代器 生成器函数的使用 生成器函数 惰性求值 延迟求值提供了可能 函数中只要有yield关键字 该函数就是生成器函数 yield 返回的是generator(生成器)对象 是可迭代的 return 只能写一个 而yield能写多个 生成器在UserList中的应用 from collection.abc import UserList UserList 使用python实现 其中__iter__ 魔法函数用到yield关键字 将该魔法函数变为生成器 依次返回下一个迭代元素 python socket编程 弄懂 HTTP、Socket、TCP 这几个概念 socket本质是编程接口 不属于任何协议 对TCP/IP协议的封装 提供给程序猿使用 与下层协议交互 在上层可自定义协议 http 应用层协议 TCP 传输层协议 client和server实现通讯 多线程、多进程和线程池编程 python 中的 GIL gil global interpreter lock (cpython) python中一个线程对应于c语言中的一个线程 gil使得同一个时刻只有一个线程在一个cpu上执行字节码, 无法将多个线程映射到多个cpu上执行 gil会根据执行的字节码行数以及时间片释放gil,gil在遇到io的操作时候主动释放 多线程编程 - threading 多线程编程的第一种方式 import threading threading.Thread(target=func, args=tuple) target 参数传入一个方法 args 参数用于传入方法参数 类型为tuple 获得线程实例后 执行 start()方法 实例的setDaemon(bool) 方法 bool为True时 可将线程设置为守护线程 即主线程结束时同时结束该守护线程 多线程编程的第二种方式 继承 threading.Thread 并实现run函数 实例化类后执行start() 方法即可 join() 方法可以阻塞主线程 等到子线程结束后 才继续执行主线程 线程间通信 - 共享变量和 Queue 共享变量 是线程不安全的 Queue Queue使用的是deque(双端队列)是线程安全的 一些方法 task_done join qsize empty full put get put_nowait get_nowait 线程同步 - Lock、RLock from threading import Lock,Rlock Lock 声明锁 Lock() lock.acquire 获取锁 lock.release 释放锁 RLock 可重入锁 #相当于java中的ReentrantLock 在同一线程中 acquire和release 操作的次数要相等 线程同步 - condition 使用以及源码分析 from threading import Condition 条件变量 用于复杂的线程间同步 配合with语句使用 进入__enter__ 方法 会对condition加锁 wait 方法执行时 会获取一个锁实例并加锁 并把wait的锁加入双端队列 同时释放condition的锁 notify方法执行时 会对双端队列中的wait锁弹出 并解锁 一些总结 启动顺序很重要 在调用with cond之后才能调用wait或者notify方法 condition有两层锁, 一把底层锁会在线程调用了wait方法的时候释放, 上面的锁会在每次调用wait的时候分配一把并放入到cond的等待队列中,等到notify方法的唤醒 线程同步 - Semaphore 使用以及源码分析 Semaphore 是用于控制进入数量的锁 #相当于java中的Semaphore from threading import Semaphore 内部使用condition完成 threading.Semaphore(num) num为并发数 acquire方法调用时 其中的计数器会+1 当计数器满时 也就是达到了num的数量时会阻塞 release 方法调用时 其中的计数器会-1 当计数器为零时 会释放锁 ThreadPoolExecutor线程池 一些总结 线程池, 为什么要线程池 主线程中可以获取某一个线程的状态或者某一个任务的状态,以及返回值 当一个线程完成的时候我们主线程能立即知道 futures可以让多线程和多进程编码接口一致 from concurrent.futures import ThreadPoolExecutor ThreadPoolExecutor(max_workers) max_workers为线程池大小 通过 submit(func, tuple) 函数提交一个方法到线程池中 func为函数 tuple为以元祖的方式给func函数传入参数 submit会立即返回一个futures类 用来监视线程状态 监视线程状态常用方法:done result cancel from concurrent.futures import as_completed 用来获取线程池中已经完成的线程 使用:传入批量的线程池返回结果 然后通过for语句迭代 如:for future in as_completed(all_task) 最后future.result得到结果 executor.map #executor为一个线程池实例 executor.map(func, *args) 同理 for result in executor.map(func, *args) 迭代直接返回结果 as_completed和executor.map的区别 as_completed 将返回先完成的进程的结果 executor.map 将返回先执行的进程的结果 from concurrent.futures import wait 可以阻塞主线程并可以指定何时继续执行主线程 如:所有线程完成之后才继续往下执行 或者只要有一个线程完成后就继续往下执行 使用:wait(fs) fs为futures序列 还有timeout(等待超时时间)参数 默认为None 和return_when(何时继续执行) 参数 默认为ALL_COMPLETED ThreadPoolExecutor源码分析 from concurrent.futures import Future “未来”对象 task的返回容器 在线程池执行submit函数有生成一个Future实例 然后将future实例和需要执行的方法放入一个_WorkItem实例中 _WorkItem又被放到_work_queue队列中 待执行 最后_adjust_thread_count方法控制线程池大小并开启线程 交给_worker方法 _worker函数负责从_work_queue队列中获取_WorkItem并执行run方法 _WorkItem.run()函数负责完成函数的执行和将最后完成的结果赋值给future实例 多线程和多进程对比 多进程使用 from concurrent.futures import ProcessPoolExecutor 包 由于api相同 所以与多线切换很容易 ThreadPoolExecutor换成ProcessPoolExecutor即可 一些总结 耗cpu的操作,用多进程编程, 对于io操作来说, 使用多线程编程,进程切换代价要高于线程 1. 对于耗费cpu的操作,多进程优于多线程 2. 对于io操作来说,多线程优于多进程 由于GIL锁的存在 多进程并行的效率要比多进程并发的效率高 耗费cpu的运算操作应该放到多个cpu上 io操作不怎么耗费cpu 但在切换的操作上 线程效率要略快与进程效率 所以io操作应该用多进程 而且cpu核数是有限的 但进程可以开很多 multiprocessing 多进程编程 os.fork 会新建子进程 只能用于Unix/Linux中 不能用在win中 子进程会继续执行fork函数后的代码 但进程间数据是完全隔离的 from concurrent.futures import ProcessPoolExecutor 底层使用的是multiprocessing 实现多进程方法 需继承 multiprocessing.Process 实现的方法与多线程类似 multiprocessing.Process(target, args) 一些方法 pid start join is_alive multiprocessing.pool() 也可以实现进程池 如果不指定线程池大小 则内部自动获取os.cpu_count()(cpu核心数)作为进程池大小 pool.apply_async() 异步提交任务 返回ApplyResult 类似Future pool.close() 关闭进程池 不再接受新任务 pool.join() 等待所有任务完成 需在pool.close() 调用之后调用 不然会报错 Pool is still running pool.imap() 同对线程池的 executor.map 同样先返回先加入的方法的结果 进程间通信 - Queue、Pipe,Manager 使用的是from multiprocessing import Queue, Manager, Pipe 多进程数据是完全隔离的 共享全局变量不能适用于多进程编程,可以适用于多线程 multiprocessing中的queue不能用于pool进程池 pool中的进程间通信需要使用Manager中的queue 需要实例化 Manager().Queue(num) Pipe实例化返回receive_pipe(接收管道) send_pipe (发送管道) 只能适用于两个进程通讯 性能要高于Queue Manager中有很多函数可以实现多进程共享一个内存块 实现类似于多线程共享全局变量 还有很多函数实现通讯同步 API类似于多线程同步API 协程和异步io 并发、并行、同步、异步、阻塞、非阻塞 并发:是指一个时间段内 有几个程序在同一个cpu上运行 但是任意时刻只有一个程序在cpu上运行 并行:是指任意时刻点上 有多个程序同时运行在多个cpu上 同步:是指代码调用IO操作时 必须等待IO操作完成才返回的调用方式 异步:是指代码调用IO操作时 不必等待IO操作完成就返回的调用方式 阻塞:是指调用函数时候当前线程被挂起 非阻塞:是指调用函数时候当前线程不会被挂起 而是立即返回 C10K问题和IO多路复用 (select、poll 和 epoll) Unix下五种I/O模型 阻塞式I/O 非阻塞式I/O I/O复用 信号驱动式I/O 异步I/O(POSIX的aio_系列函数) select poll epoll是一个改良的过程 epoll并不代表一定比select好 在并发高的情况下,连接活跃度不是很高, epoll比select 并发性不高,同时连接很活跃, select比epoll好 select+回调+事件循环获取html 使用非阻塞IO完成http请求 client.setblocking(False) 设置非阻塞IO完成http请求 立马返回 但需要不断的while循环 尝试在连接建立后 执行操作 使用select完成http请求 #参考java NIO中的Selector编程 注册 selector.register(self.client.fileno(), EVENT_WRITE, self.connected) self.client.fileno()为文件描述符 EVENT_WRITE 为事件 辨识可写事件 self.connected 为回调函数 当client连接建立成功时 回调执行 selector.register(self.client.fileno(), EVENT_READ, self.readable) self.client.fileno()为文件描述符 EVENT_READ 为事件 辨识可读事件 self.readable 为回调函数 当client接收到数据时 回调执行 注销 selector.unregister(key.fd) key为注册事件标识 key为注册时self.client.fileno()的返回值 回调 事件循环,不停的请求socket的状态并调用对应的回调函数 select本身是不支持register模式 socket状态变化以后的回调是由程序员完成的 selector.select() 返回ready ready返回 key和mask 其中 key.data 返回注册时的回调函数 回调之痛 可读性差 共享状态管理困难 异常处理困难 协程是什么 C10M问题 一些编程问题 回调模式编码复杂度高 同步编码的并发性不高 多线程编程需要线程同步锁 协程 传统函数调用 过程 A->B->C 我们需要一个可以暂停的函数,并且可以在适当的时候恢复该函数的继续执行 出现了协程 -> 有多个入口的函数, 可以暂停的函数, 可以暂停的函数(可以向暂停的地方传入值) 协程需求:暂停 传值 抛异常 关闭 采用同步的方式去编写异步的代码 在适当的时候暂停函数并在适当的时候启动函数 使用单线程去切换任务 线程是由操作系统切换的 单线程切换意味着我们需要程序员自己去调度任务 不在需要锁 并发性高 如果单线程内切换函数 性能远高于线程切换 并发性更高 生成器进阶-send、close和throw方法 生成器可以暂停 生成器不仅可以产出值 还可以接受值 启动生成器有两种 next() 和send() next() (暂停) send() (暂停 传值) 方法可以传递值进入生成器内部 同时还可以重启生成器 执行下一个yield位置 用send发送非none值之前,我们必须启动一次生成器, 方式有两种1. gen.send(None), 2. next(gen) close() (关闭) 会抛出 GeneratorExit 异常 是继承自BaseException 如果捕获后 做pass 处理且后边还有yield语句 close的地方就会抛出 RuntimeError 如果捕获后 raise StopIteration 则不会再抛出异常 所以这个异常不需要去捕获 throw() (抛异常) 给当前yield语句抛出异常 生成器进阶-yield from from itertools import chain 可以连接可迭代类型 然后在一个for中迭代 yield和yield from的区别 yield只返回原始的结果 yield from 会依次返回可迭代对象中的元素 yield from main()——>gen():yield from gen_child() yield from会在调用方(main())与子生成器(gen_child())之间建立一个双向通道 会处理StopIteration等异常以及将结果返回 一些总结 简化版 1. 子生成器可能只是一个迭代器,并不是一个作为协程的生成器,所以它不支持.throw()和.close()方法; 2. 如果子生成器支持.throw()和.close()方法,但是在子生成器内部,这两个方法都会抛出异常; 3. 调用方让子生成器自己抛出异常 4. 当调用方使用next()或者.send(None)时,都要在子生成器上调用next()函数,当调用方使用.send()发送非 None 值时,才调用子生成器的.send()方法; 完整版 1. 子生成器生产的值,都是直接传给调用方的;调用方通过.send()发送的值都是直接传递给子生成器的;如果发送的是 None,会调用子生成器的__next__()方法,如果不是 None,会调用子生成器的.send()方法; 2. 子生成器退出的时候,最后的return EXPR,会触发一个StopIteration(EXPR)异常; 3. yield from表达式的值,是子生成器终止时,传递给StopIteration异常的第一个参数; 4. 如果调用的时候出现StopIteration异常,委托生成器会恢复运行,同时其他的异常会向上 “冒泡”; 5. 传入委托生成器的异常里,除了GeneratorExit之外,其他的所有异常全部传递给子生成器的.throw()方法;如果调用.throw()的时候出现了StopIteration异常,那么就恢复委托生成器的运行,其他的异常全部向上 “冒泡”; 6. 如果在委托生成器上调用.close()或传入GeneratorExit异常,会调用子生成器的.close()方法,没有的话就不调用。如果在调用.close()的时候抛出了异常,那么就向上 “冒泡”,否则的话委托生成器会抛出GeneratorExit异常。 async和await python为了将语义变得更加明确,就引入了async和await关键词用于定义原生的协程 原生协程不能使用next(None)方法预激协程 必须使用send(None)方法 使用async 关键词定义协程方法 await 只接受async关键字定义的协程方法或者使用@types.coroutine装饰器装饰方法(该装饰器在import types包中 包装方法并实现__await__魔法方法) 生成器实现协程 使用import inspect包中inspect.getgeneratorstate()获取生成器状态 如 GEN_CREATED GEN_SUSPENDED GEN_CLOSED 协程的调度依然是 事件循环+协程模式 协程是单线程模式 asyncio并发编程 事件循环 asyncio #参考java中的AIO 包含各种特定系统实现的模块化事件循环 传输和协议抽象 对TCP UDP SSL 子进程 延时调用以及其他的具体支持 模仿futures模块但适用于事件循环使用的Future类 基于yield from 的协议和任务 可以让你用顺序的方式编写并发代码 必须使用一个将产生阻塞IO的调用时 有接口可以把这个事件转移到线程池 模仿threading模块中的同步原语 可以用在单线程内的协程之间 一些总结 事件循环+回调(驱动生成器)+epoll(IO多路复用) asyncio是python用于解决异步io编程的一整套解决方案 tornado、gevent、twisted(scrapy, django channels) torando(实现web服务器), django+flask(uwsgi, gunicorn+nginx) tornado可以直接部署, nginx+tornado 一些使用 在协程编码中不能使用非异步阻塞方法 loop=asyncio.get_event_loop() 异步事件循环 可以看做协程池 loop.run_until_complete() 阻塞方法 直到协程方法执行完之后才往下执行 可以接收协程类型 协程的future类型 协程的task 类型 #相当于多线程中的join() asyncio.wait() 接收可迭代异步对象 asyncio.sleep() 异步IO的sleep 需在前边加await关键字 获取协程的返回值 asyncio.ensure_future() 内部使用loop.create_task将协程包装成task task.add_done_callback() 为协程添加回调方法 future会作为参数传入回调函数中 from functools import partial 偏函数 可以包装函数 重新定义函数签名 asyncio.wait 相当于多线程中的wait 可以指定何时结束 asyncio.gather 与wait用法类似 但可以将协程分组 等待组完成后结束 task取消和子协程调用原理 task取消 run_until_complete 内部使用run_forever() 但为future添加了个一个回调函数future.add_done_callback(_run_until_complete_cb) 当future完成时调用_run_until_complete_cb(fut) 在其中执行fut._loop.stop() 将事件循环停止 即将事件停止标识为True self._stopping = True loop会被放到future中 asyncio.Task.all_tasks() 从loop中获取所有task task.cancel() 取消task 返回True取消成功 返回False取消失败 loop.stop() 停止loop loop.run_forever() 重新运行loop loop.close() 最后关闭loop 子协程调用 #参考 与yield from相同 call_soon、call_at、call_later、call_soon_threadsafe loop.call_soon() 将回调函数加入FIFO队列 并按照注册顺序尽可能的回调返回 loop.call_at 在loop某一时间点回调 用到loop.time() loop.call_later() 在指定时间后回调 loop.call_soon_threadsafe() 是loop.call_soon() 的线程安全版 ThreadPollExecutor 和 asycio 完成阻塞 IO 请求 loop.run_in_executor(executor, func, *args ) executor为线程池实例 func为放入线程池中的函数 *args为func参数 返回task 然后交给loop运行 asyncio 模拟 http 请求 await asyncio.open_connection(host,port) 语句 等待建立连接 返回 reader 和writer reader用于接收响应 writer用于发送请求 async for 语法 异步for循环 调用__anext__魔法函数 asyncio.as_completed(tasks) 返回一个由@coroutine修饰的 _wait_for_one() 协程 其中才返回 f.result() 所以for得到的task前需要要加await 等待返回结果 #与多线程类似 future 和 task future 由于协程的单线程的原因 获取结果时执行_schedule_callbacks(self) 其中通过for循环获取 self._callbacks列表中的callback 然后执行self._loop.call_soon(callback, self) task Task是Future的子类 是协程和Future之间的桥梁 task在__init__时调用__step通过send(None)预激了协程 task捕获在协程最后return时抛出的StopIteration异常 并通过self.set_result(exc.value)设置返回结果 asyncio同步和通信 from asyncio import Lock, Queue 使用:await lock.acquire() 或 with await lock 或 async with lock with await lock 或 async with lock 分别执行的是__await__和@coroutine修饰的__aenter__魔法函数 参考 慕课]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>python</tag>
</tags>
</entry>
<entry>
<title><![CDATA[我喜欢的音乐]]></title>
<url>%2Fmy-favorite-songs%2F</url>
<content type="text"><![CDATA[经过挺久的收藏 网易云音乐的收藏也快两百了 什么都有 日语和女音居多 女毒 电音 慢歌 快歌 空灵 古风 纯音乐 RainyMood Game(Gal)/动画TV(OP/ED/IN/OST/REMIX/角色歌) 鬼畜洗脑 重低音 广播(CV) 少量V+和翻唱]]></content>
<categories>
<category>音乐</category>
</categories>
<tags>
<tag>网易云</tag>
<tag>音乐</tag>
</tags>
</entry>
<entry>
<title><![CDATA[索尼SVF15326SCB黑苹果后]]></title>
<url>%2Fhackintosh%2F</url>
<content type="text"><![CDATA[因为旧本本只有机械硬盘 把光驱位拆了后 弄了块SSD 于是想着折腾一下黑苹果 装完后并不完美 踩了不少坑 独显和内置无线网卡折腾了很久无解 本文提供的是索尼SVF15326SCB型号的有效装配 其他型号仅作参考和提供思路 均为基本操作并未究其原理 如需其他帮助可转社区 清单 我的CLOVER 百度云 tyhu 软件工具 Clover Configurator Kext Wizard AppleHDA Patcher MaciASL 驱动[1] RealtekRTL8111.kext AppleALC.kext VoodooHDA.kext ACPIBacklight.kext ACPIBatteryManager.kext 我的config.plist 这是打过补丁或修改后的最终版 config.plist 点击展开 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict> <key>ACPI</key> <dict> <key>DSDT</key> <dict> <key>Debug</key> <false/> <key>ReuseFFFF</key> <false/> </dict> <key>DropTables</key> <array> <dict> <key>Signature</key> <string>DMAR</string> </dict> </array> <key>SSDT</key> <dict> <key>DropOem</key> <false/> <key>Generate</key> <dict> <key>APLF</key> <true/> <key>APSN</key> <true/> <key>CStates</key> <true/> <key>PStates</key> <true/> <key>PluginType</key> <true/> </dict> </dict> </dict> <key>Boot</key> <dict> <key>Arguments</key> <string>dart=0 -xcpm nv_disable=1 kext-dev-mode=1</string> <key>Debug</key> <false/> <key>Legacy</key> <string>LegacyBiosDefault</string> <key>Secure</key> <false/> <key>Timeout</key> <integer>5</integer> <key>XMPDetection</key> <false/> </dict> <key>CPU</key> <dict> <key>UseARTFrequency</key> <false/> </dict> <key>Devices</key> <dict> <key>Audio</key> <dict> <key>Inject</key> <string>3</string> </dict> <key>FakeID</key> <dict> <key>IntelGFX</key> <string>0x04128086</string> </dict> <key>SetIntelBacklight</key> <true/> <key>USB</key> <dict> <key>AddClockID</key> <true/> <key>FixOwnership</key> <true/> <key>Inject</key> <true/> </dict> </dict> <key>GUI</key> <dict> <key>Custom</key> <dict> <key>Entries</key> <array> <dict> <key>Disabled</key> <false/> <key>FullTitle</key> <string>UEFI Internal</string> <key>Hidden</key> <string>Always</string> <key>Ignore</key> <false/> <key>NoCaches</key> <false/> <key>Type</key> <string>Other</string> </dict> </array> </dict> <key>Language</key> <string>en:0</string> <key>Mouse</key> <dict> <key>DoubleClick</key> <integer>500</integer> <key>Enabled</key> <false/> <key>Mirror</key> <false/> <key>Speed</key> <integer>8</integer> </dict> <key>Scan</key> <dict> <key>Entries</key> <true/> <key>Legacy</key> <false/> <key>Linux</key> <false/> <key>Tool</key> <false/> </dict> </dict> <key>Graphics</key> <dict> <key>Inject</key> <dict> <key>ATI</key> <false/> <key>Intel</key> <true/> <key>NVidia</key> <false/> </dict> <key>NvidiaSingle</key> <false/> <key>ig-platform-id</key> <string>0x0a260006</string> </dict> <key>KernelAndKextPatches</key> <dict> <key>AppleIntelCPUPM</key> <true/> <key>AppleRTC</key> <true/> <key>Debug</key> <false/> <key>DellSMBIOSPatch</key> <false/> <key>KernelCpu</key> <true/> <key>KernelLapic</key> <false/> <key>KernelPm</key> <true/> <key>KernelXCPM</key> <false/> <key>KextsToPatch</key> <array> <dict> <key>Comment</key> <string>Enable Trim on SSD</string> <key>Disabled</key> <false/> <key>Find</key> <data> QVBQTEUgU1NE </data> <key>Name</key> <string>IOAHCIBlockStorage</string> <key>Replace</key> <data> AAAAAAAAAAAA </data> </dict> <dict> <key>Comment</key> <string>Boot graphics glitch, 10.10.x/10.11.x (credit lisai9093, cecekpawon)</string> <key>Disabled</key> <true/> <key>Find</key> <data> AQAAdRc= </data> <key>Name</key> <string>com.apple.iokit.IOGraphicsFamily</string> <key>Replace</key> <data> AQAA6xc= </data> </dict> </array> </dict> <key>RtVariables</key> <dict> <key>BooterConfig</key> <string>0x28</string> <key>CsrActiveConfig</key> <string>0x67</string> </dict> <key>SMBIOS</key> <dict> <key>BiosReleaseDate</key> <string>10/18/13</string> <key>BiosVendor</key> <string>Apple Inc.</string> <key>BiosVersion</key> <string>MBP112.88Z.0138.B02.1310181745</string> <key>Board-ID</key> <string>Mac-3CBD00234E554E41</string> <key>BoardManufacturer</key> <string>Apple Inc.</string> <key>BoardSerialNumber</key> <string>C023118TUDJ3Q</string> <key>BoardType</key> <integer>10</integer> <key>ChassisAssetTag</key> <string>MacBook-Aluminum</string> <key>ChassisManufacturer</key> <string>Apple Inc.</string> <key>ChassisType</key> <string>8</string> <key>Family</key> <string>MacBook Pro</string> <key>Manufacturer</key> <string>Apple Inc.</string> <key>Memory</key> <dict> <key>Channels</key> <integer>1</integer> <key>Modules</key> <array> <dict> <key>Frequency</key> <integer>1600</integer> <key>Part</key> <string>CE M471B5173QH0-YK0</string> <key>Serial</key> <string>19342E80</string> <key>Size</key> <integer>4096</integer> <key>Slot</key> <integer>0</integer> <key>Type</key> <string>DDR3</string> <key>Vendor</key> <string>kingston</string> </dict> <dict> <key>Frequency</key> <integer>1600</integer> <key>Part</key> <string>CE M471B5173QH0-YK0</string> <key>Serial</key> <string>14CFE8BB</string> <key>Size</key> <integer>4096</integer> <key>Slot</key> <integer>1</integer> <key>Type</key> <string>DDR3</string> <key>Vendor</key> <string>kingston</string> </dict> </array> <key>SlotCount</key> <integer>2</integer> </dict> <key>Mobile</key> <true/> <key>ProductName</key> <string>MacBookPro11,2</string> <key>SerialNumber</key> <string>C02L5Q0RFD56</string> <key>Trust</key> <true/> <key>Version</key> <string>1.0</string> </dict> <key>SystemParameters</key> <dict> <key>InjectKexts</key> <string>Detect</string> </dict></dict></plist> 有线网卡 网卡在装完黑苹果之后就能用了 用的 RealtekRTL8111.kext驱动 放到EFI/CLOVER/kexts/xxx/下就行 声卡 黑后发现 声卡并不能使用 然后找遍了驱动 AppleALC.kext 安装AppleALC.kext 可以用Kext Wizard安装到系统中 但推荐直接将驱动文件放入EFI/CLOVER/kexts/xxx/驱动文件夹中 设置layout 使用Clover Configurator设置Devices-Audio-Inject为3[2] 修复 HPET 使用Clover Configurator勾选Acpi-Fixes-FixHPET选项 安装后声卡虽然可以使用了 但是后来发现声音输入无电平 QQ开语音会强制重启 睡眠唤醒后无法使用的情况 后来改用VoodooHDA.kext驱动 VoodooHDA.kext 安装VoodooHDA.kext 直接将VoodooHDA.kext驱动拖进clover的EFI/CLOVER/kexts/xxx/驱动文件夹中即可 可能需要的额外操作 将VoodooHdaSettingsLoader加入登录项 安装AppleHDADisabler.kext驱动 安装VoodooHDA.prefPane系统偏好设置 AppleHDA.kext 第三种方案 虽然可行 但是貌似没有VoodooHDA.kext好使 使用AppleHDA Patcher给原生AppleHDA.kext驱动打补丁[3] 注意备份原始AppleHDA.kext驱动 显卡 集显虽然正常使用 但是还有些细节不完美 无法调节亮度 休眠唤醒后黑屏 亮度调节DSDT补丁[4] 这里使用的是RehabMan的[igpu]Haswell HD4400/HD4600/HD5000补丁 获取系统DSDT文件 使用clover引导界提取 在clover引导界面按F4会将所有ACPI相关的文件提取到EFI/CLOVER/ACPI/origin中 找到DSDT.aml文件 使用MaciASL提取 打开MaciASL 在菜单栏File-Now From ACPI-DSDT 修改后另存为(Save As)即可 给DSDT打补丁 给MaciASL添加Sources 打开MaciASL设置 MaciASL-Preferences-Sources 在Patch Sources中添加一个Sources Name为RehabMan Laptop(随意) URL为http://raw.github.com/RehabMan/Laptop-DSDT-Patch/master 打补丁 将提取出来的DSDT.aml拖进MaciASL然后编辑 点击Patch按钮找到RehabMan Laptop-[igpu]Haswell HD4400/HD4600/HD5000 选中后点击Apply 再点击Close回到MaciASL主界面 点击Compile编译 添加补丁后的DSDT.aml到EFI 将补丁后的DSDT.aml放至EFI/CLOVER/ACPI/patched中即可 可能需要的额外操作 安装ACPIBacklight.kext驱动 修复休眠唤醒后黑屏 休眠唤醒后黑屏其实是屏幕亮度调到了最低 使用Clover Configurator勾选Devices-Properties-SetIntelBacklight 内存 内存没什么大问题 就是在关于本机中显示乱码(就是有点强迫症) 使用Clover Configurator在SMBIOS-Memory中添加内存先关信息即可: 这些内存条信息可以用鲁大师或者GPU-Z查看 参数 说明 栗子🌰 Slot 内存条插槽位 0 Size 内存条大小(MB) 4096 Frequency 内存频率(Mhz) 1600 Vendor 内存条厂商 kingston Part 内存条型号 CE M471B5173QH0-YK0 Serial 内存条序列号 19342E80 Type 内存条规格 DDR3 Channels 是否多通道 Single Channel SlotCount 内存条数 2 无线网卡 由于内置网卡无解 只能用USB网卡 我用的是EP-N8508GS 到官方下载Mac驱动安装包安装即可 电池 黑后无法显示电池电量 打补丁 和给显卡打补丁一样 同样 使用的是RehabMan的[bat]Sony VAIO SVE补丁 安装驱动 电池驱动使用的是RehabMan的ACPIBatteryManager.kext 放入EFI/CLOVER/kexts/xxx/驱动文件夹中即可 蓝牙 获取VID、PID 获取VID、PID的方法应该很多 设备管理器就行 设备管理器>>>蓝牙>>>BCM43142 Bluetooth Adapter(自己的蓝牙适配器)>>>右键属性>>>详细信息>>>硬件id>>>USB\VID_0489&PID_E062&REV_0112 然后将VID、PID十六进制值分别转为十进制 0489>>>1161和E062>>>57442 修改原生驱动info.plist 文件路径: /System/Library/Extensions/IOBluetoothFamily.kext/Contents/PlugIns/BroadcomBluetoothHostControllerUSBTransport.kext/Contents/Info.plist 将idVendor和idVendor的值改为对应的值即可 1234<key>idProduct</key><integer>57442</integer><key>idVendor</key><integer>1161</integer> 参考 驱动下载 ↩︎ layout参考 ↩︎ AppleHDA参考 ↩︎ 亮度调节 ↩︎]]></content>
<categories>
<category>手记</category>
</categories>
<tags>
<tag>黑苹果</tag>
<tag>折腾</tag>
</tags>
</entry>
<entry>
<title><![CDATA[《Thinking in java》读书笔记]]></title>
<url>%2Fthinking-in-java%2F</url>
<content type="text"><![CDATA[《Thinking in java》的读书笔记 持续并慢慢地更新着 本笔记仅作为个人笔记 内容可能并不适用于所有群体 属于总结性质 需要详细内容就去买本书并支持一下吧 一本好书的灵魂在于有思想 第13章 字符串 13.1 不可变String String对象是不可变的。String类中每一个看起来修改String值的方法,实际上是创建了一个全新的String对象,以包含修改后的字符串内容。而最初的String对象值不变。]]></content>
<categories>
<category>笔记</category>
</categories>
<tags>
<tag>java</tag>
<tag>读书</tag>
<tag>thinking</tag>
</tags>
</entry>
<entry>
<title><![CDATA[SSH的简单使用]]></title>
<url>%2Fusage-of-the-ssh%2F</url>
<content type="text"><![CDATA[ssh免密码登入 生成密钥 123$ ssh-keygen [-t dsa | ecdsa | ed25519 | rsa | rsa1] //加密方式 [-C comment] //注释 [-f output_keyfile] //密钥文件保存位置 如不做其他设置一路回车即可 生成密钥后找到密钥文件 如未设置保存路径 则默认保存在 ~/.ssh/ 包括id_[-t dsa | ecdsa | ed25519 | rsa | rsa1] 和id_[-t dsa | ecdsa | ed25519 | rsa | rsa1].pub文件 将公钥上传至远程linux服务器 将id_xxx.pub文件中的内容追加到远程服务器~/.ssh/authorized_keys文件中 没有则自行创建 注 ~为user home ssh-copy-id ssh-copy-id命令可以把本地主机的公钥复制到远程主机的authorized_keys文件上,ssh-copy-id命令也会给远程主机的用户主目录(home)和~/.ssh, 和~/.ssh/authorized_keys设置合适的权限。 12$ ssh-copy-id [-i [identity_file]] //本地的ssh公钥文件路径 [user@]hostname //远程主机 scp scp命令用于在Linux下进行远程拷贝文件的命令,和它类似的命令有cp,不过cp只是在本机进行拷贝不能跨服务器,而且scp传输是加密的。 123$ scp [-i identity_file] //本地ssh公钥文件 [-P port] //远程端口 [[user@]host1:]file //指定远程路径 然后将公钥内容追加到远程服务器~/.ssh/authorized_keys文件中 1$ cat id_xxx.pub >> ~/.ssh/authorized_keys 手动 在本地ctrl+c复制id_xxx.pub中的密钥 然后在服务器端: 1$ echo "ctrl+v" >> ~/.ssh/authorized_keys 登录 12ssh [-p port] //远程端口 [user@]hostname //登录用户名和远程主机 参考 ArchWiki linuxde]]></content>
<categories>
<category>杂记</category>
</categories>
<tags>
<tag>linux</tag>
<tag>ssh</tag>
</tags>
</entry>
<entry>
<title><![CDATA[心愿]]></title>
<url>%2Fwishes%2F</url>
<content type="text"><![CDATA[想要买和读的书 [x] 《Think In Java》 [ ] 《Effective Java》 [ ] 《Hadoop权威指南》 [ ] 《Deep Learning 深度学习》 配件 [ ] 组装双屏升降显示器 [ ] MBP [ ] 一只猫(我一定会有猫的!(有生之年QWQ]]></content>
<categories>
<category>想</category>
</categories>
<tags>
<tag>书</tag>
<tag>配件</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Hello World]]></title>
<url>%2Fhello-world%2F</url>
<content type="text"><![CDATA[Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub. Quick Start Create a new post 1$ hexo new "My New Post" More info: Writing Run server 1$ hexo server More info: Server Generate static files 1$ hexo generate More info: Generating Deploy to remote sites 1$ hexo deploy More info: Deployment]]></content>
</entry>
</search>