Explore the full ebook collection and download it now at textbookfull.com
High Performance Python Practical Performant
Programming for Humans 2nd Edition Micha Gorelick
Ian Ozsvald
https://textbookfull.com/product/high-performance-python-
practical-performant-programming-for-humans-2nd-edition-
micha-gorelick-ian-ozsvald/
OR CLICK HERE
DOWLOAD EBOOK
Browse and Get More Ebook Downloads Instantly at https://textbookfull.com
Click here to visit textbookfull.com and download textbook now
Your digital treasures (PDF, ePub, MOBI) await
Download instantly and pick your perfect format...
Read anywhere, anytime, on any device!
Parallel programming for modern high performance computing
systems Czarnul
https://textbookfull.com/product/parallel-programming-for-modern-high-
performance-computing-systems-czarnul/
textbookfull.com
Automate the Boring Stuff with Python, 2nd Edition:
Practical Programming for Total Beginners Al Sweigart
https://textbookfull.com/product/automate-the-boring-stuff-with-
python-2nd-edition-practical-programming-for-total-beginners-al-
sweigart/
textbookfull.com
Black Hat Python: Python Programming for Hackers and
Pentesters 2nd Edition Justin Seitz
https://textbookfull.com/product/black-hat-python-python-programming-
for-hackers-and-pentesters-2nd-edition-justin-seitz/
textbookfull.com
Julia High Performance 2nd Edition Avik Sengupta
https://textbookfull.com/product/julia-high-performance-2nd-edition-
avik-sengupta/
textbookfull.com
Beginning Programming with Python For Dummies 2nd Edition
John Paul Mueller
https://textbookfull.com/product/beginning-programming-with-python-
for-dummies-2nd-edition-john-paul-mueller/
textbookfull.com
Practical Foundations For Programming Languages 2nd
Edition Robert Harper
https://textbookfull.com/product/practical-foundations-for-
programming-languages-2nd-edition-robert-harper/
textbookfull.com
Routledge Handbook of Strength and Conditioning Sport
Specific Programming for High Performance Anthony Turner
https://textbookfull.com/product/routledge-handbook-of-strength-and-
conditioning-sport-specific-programming-for-high-performance-anthony-
turner/
textbookfull.com
A Practical Approach to High-Performance Computing Sergei
Kurgalin
https://textbookfull.com/product/a-practical-approach-to-high-
performance-computing-sergei-kurgalin/
textbookfull.com
Python Network Programming Cookbook Practical solutions to
overcome real world networking challenges 2nd Edition
Pradeeban Kathiravelu
https://textbookfull.com/product/python-network-programming-cookbook-
practical-solutions-to-overcome-real-world-networking-challenges-2nd-
edition-pradeeban-kathiravelu/
textbookfull.com
S
e
c
o
n
d
E
d
i
t
i
o
n
Micha Gorelick & Ian Ozsvald
High
Performance
Python
Practical Performant
Programming for Humans
Micha Gorelick and Ian Ozsvald
High Performance Python
Practical Performant Programming for Humans
SECOND EDITION
Boston Farnham Sebastopol Tokyo
Beijing Boston Farnham Sebastopol Tokyo
Beijing
978-1-492-05502-0
[LSI]
High Performance Python
by Micha Gorelick and Ian Ozsvald
Copyright © 2020 Micha Gorelick and Ian Ozsvald. All rights reserved.
Printed in the United States of America.
Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472.
O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are
also available for most titles (http://oreilly.com). For more information, contact our corporate/institu‐
tional sales department: 800-998-9938 or corporate@oreilly.com.
Acquisitions Editor: Tyler Ortman Indexer: Potomac Indexing, LLC
Development Editor: Sarah Grey Interior Designer: David Futato
Production Editor: Christopher Faucher Cover Designer: Karen Montgomery
Copyeditor: Arthur Johnson Illustrator: Rebecca Demarest
Proofreader: Sharon Wilkey
September 2014: First Edition
May 2020: Second Edition
Revision History for the Second Edition
2020-04-30: First release
See http://oreilly.com/catalog/errata.csp?isbn=9781492055020 for release details.
The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. High Performance Python, the cover
image, and related trade dress are trademarks of O’Reilly Media, Inc.
The views expressed in this work are those of the authors, and do not represent the publisher’s views.
While the publisher and the authors have used good faith efforts to ensure that the information and
instructions contained in this work are accurate, the publisher and the authors disclaim all responsibility
for errors or omissions, including without limitation responsibility for damages resulting from the use of
or reliance on this work. Use of the information and instructions contained in this work is at your own
risk. If any code samples or other technology this work contains or describes is subject to open source
licenses or the intellectual property rights of others, it is your responsibility to ensure that your use
thereof complies with such licenses and/or rights.
High Performance Python is available under the Creative Commons Attribution-NonCommercial-
NoDerivs 3.0 International License.
Table of Contents
Foreword. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi
Preface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii
1. Understanding Performant Python. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
The Fundamental Computer System 2
Computing Units 2
Memory Units 5
Communications Layers 8
Putting the Fundamental Elements Together 10
Idealized Computing Versus the Python Virtual Machine 10
So Why Use Python? 14
How to Be a Highly Performant Programmer 16
Good Working Practices 17
Some Thoughts on Good Notebook Practice 19
Getting the Joy Back into Your Work 20
2. Profiling to Find Bottlenecks. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Profiling Efficiently 22
Introducing the Julia Set 23
Calculating the Full Julia Set 26
Simple Approaches to Timing—print and a Decorator 30
Simple Timing Using the Unix time Command 33
Using the cProfile Module 35
Visualizing cProfile Output with SnakeViz 39
Using line_profiler for Line-by-Line Measurements 40
Using memory_profiler to Diagnose Memory Usage 46
Introspecting an Existing Process with PySpy 54
iii
Bytecode: Under the Hood 55
Using the dis Module to Examine CPython Bytecode 55
Different Approaches, Different Complexity 57
Unit Testing During Optimization to Maintain Correctness 59
No-op @profile Decorator 60
Strategies to Profile Your Code Successfully 62
Wrap-Up 64
3. Lists and Tuples. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
A More Efficient Search 68
Lists Versus Tuples 71
Lists as Dynamic Arrays 72
Tuples as Static Arrays 76
Wrap-Up 77
4. Dictionaries and Sets. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
How Do Dictionaries and Sets Work? 83
Inserting and Retrieving 83
Deletion 87
Resizing 87
Hash Functions and Entropy 88
Dictionaries and Namespaces 92
Wrap-Up 95
5. Iterators and Generators. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Iterators for Infinite Series 101
Lazy Generator Evaluation 103
Wrap-Up 107
6. Matrix and Vector Computation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
Introduction to the Problem 110
Aren’t Python Lists Good Enough? 115
Problems with Allocating Too Much 117
Memory Fragmentation 120
Understanding perf 122
Making Decisions with perf’s Output 125
Enter numpy 126
Applying numpy to the Diffusion Problem 129
Memory Allocations and In-Place Operations 133
Selective Optimizations: Finding What Needs to Be Fixed 137
numexpr: Making In-Place Operations Faster and Easier 140
A Cautionary Tale: Verify “Optimizations” (scipy) 142
iv | Table of Contents
Lessons from Matrix Optimizations 143
Pandas 146
Pandas’s Internal Model 146
Applying a Function to Many Rows of Data 148
Building DataFrames and Series from Partial Results Rather than
Concatenating 156
There’s More Than One (and Possibly a Faster) Way to Do a Job 157
Advice for Effective Pandas Development 159
Wrap-Up 160
7. Compiling to C. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
What Sort of Speed Gains Are Possible? 162
JIT Versus AOT Compilers 164
Why Does Type Information Help the Code Run Faster? 164
Using a C Compiler 165
Reviewing the Julia Set Example 166
Cython 167
Compiling a Pure Python Version Using Cython 167
pyximport 169
Cython Annotations to Analyze a Block of Code 170
Adding Some Type Annotations 172
Cython and numpy 176
Parallelizing the Solution with OpenMP on One Machine 178
Numba 180
Numba to Compile NumPy for Pandas 182
PyPy 183
Garbage Collection Differences 184
Running PyPy and Installing Modules 185
A Summary of Speed Improvements 186
When to Use Each Technology 187
Other Upcoming Projects 188
Graphics Processing Units (GPUs) 189
Dynamic Graphs: PyTorch 190
Basic GPU Profiling 193
Performance Considerations of GPUs 194
When to Use GPUs 196
Foreign Function Interfaces 197
ctypes 199
cffi 201
f2py 204
CPython Module 207
Wrap-Up 211
Table of Contents | v
8. Asynchronous I/O. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
Introduction to Asynchronous Programming 215
How Does async/await Work? 218
Serial Crawler 219
Gevent 221
tornado 226
aiohttp 229
Shared CPU–I/O Workload 233
Serial 233
Batched Results 235
Full Async 238
Wrap-Up 243
9. The multiprocessing Module. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
An Overview of the multiprocessing Module 248
Estimating Pi Using the Monte Carlo Method 250
Estimating Pi Using Processes and Threads 251
Using Python Objects 252
Replacing multiprocessing with Joblib 260
Random Numbers in Parallel Systems 263
Using numpy 264
Finding Prime Numbers 267
Queues of Work 273
Verifying Primes Using Interprocess Communication 278
Serial Solution 283
Naive Pool Solution 284
A Less Naive Pool Solution 285
Using Manager.Value as a Flag 286
Using Redis as a Flag 288
Using RawValue as a Flag 290
Using mmap as a Flag 291
Using mmap as a Flag Redux 293
Sharing numpy Data with multiprocessing 295
Synchronizing File and Variable Access 301
File Locking 302
Locking a Value 305
Wrap-Up 308
10. Clusters and Job Queues. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
Benefits of Clustering 312
Drawbacks of Clustering 313
$462 Million Wall Street Loss Through Poor Cluster Upgrade Strategy 315
vi | Table of Contents
Skype’s 24-Hour Global Outage 315
Common Cluster Designs 316
How to Start a Clustered Solution 317
Ways to Avoid Pain When Using Clusters 318
Two Clustering Solutions 319
Using IPython Parallel to Support Research 319
Parallel Pandas with Dask 322
NSQ for Robust Production Clustering 326
Queues 327
Pub/sub 328
Distributed Prime Calculation 330
Other Clustering Tools to Look At 334
Docker 335
Docker’s Performance 335
Advantages of Docker 339
Wrap-Up 340
11. Using Less RAM. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341
Objects for Primitives Are Expensive 342
The array Module Stores Many Primitive Objects Cheaply 344
Using Less RAM in NumPy with NumExpr 346
Understanding the RAM Used in a Collection 350
Bytes Versus Unicode 352
Efficiently Storing Lots of Text in RAM 353
Trying These Approaches on 11 Million Tokens 354
Modeling More Text with Scikit-Learn’s FeatureHasher 362
Introducing DictVectorizer and FeatureHasher 362
Comparing DictVectorizer and FeatureHasher on a Real Problem 365
SciPy’s Sparse Matrices 366
Tips for Using Less RAM 370
Probabilistic Data Structures 371
Very Approximate Counting with a 1-Byte Morris Counter 372
K-Minimum Values 375
Bloom Filters 379
LogLog Counter 385
Real-World Example 389
12. Lessons from the Field. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
Streamlining Feature Engineering Pipelines with Feature-engine 394
Feature Engineering for Machine Learning 394
The Hard Task of Deploying Feature Engineering Pipelines 395
Leveraging the Power of Open Source Python Libraries 395
Table of Contents | vii
Feature-engine Smooths Building and Deployment of Feature Engineering
Pipelines 396
Helping with the Adoption of a New Open Source Package 397
Developing, Maintaining, and Encouraging Contribution to Open Source
Libraries 398
Highly Performant Data Science Teams 400
How Long Will It Take? 400
Discovery and Planning 401
Managing Expectations and Delivery 402
Numba 403
A Simple Example 404
Best Practices and Recommendations 405
Getting Help 409
Optimizing Versus Thinking 409
Adaptive Lab’s Social Media Analytics (2014) 412
Python at Adaptive Lab 413
SoMA’s Design 413
Our Development Methodology 414
Maintaining SoMA 414
Advice for Fellow Engineers 415
Making Deep Learning Fly with RadimRehurek.com (2014) 415
The Sweet Spot 416
Lessons in Optimizing 417
Conclusion 420
Large-Scale Productionized Machine Learning at Lyst.com (2014) 420
Cluster Design 420
Code Evolution in a Fast-Moving Start-Up 421
Building the Recommendation Engine 421
Reporting and Monitoring 422
Some Advice 422
Large-Scale Social Media Analysis at Smesh (2014) 422
Python’s Role at Smesh 423
The Platform 423
High Performance Real-Time String Matching 424
Reporting, Monitoring, Debugging, and Deployment 425
PyPy for Successful Web and Data Processing Systems (2014) 426
Prerequisites 427
The Database 428
The Web Application 428
OCR and Translation 429
Task Distribution and Workers 429
Conclusion 429
viii | Table of Contents
Task Queues at Lanyrd.com (2014) 430
Python’s Role at Lanyrd 430
Making the Task Queue Performant 431
Reporting, Monitoring, Debugging, and Deployment 431
Advice to a Fellow Developer 431
Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
Table of Contents | ix
Foreword
When you think about high performance computing, you might imagine giant clus‐
ters of machines modeling complex weather phenomena or trying to understand sig‐
nals in data collected about far-off stars. It’s easy to assume that only people building
specialized systems should worry about the performance characteristics of their code.
By picking up this book, you’ve taken a step toward learning the theory and practices
you’ll need to write highly performant code. Every programmer can benefit from
understanding how to build performant systems.
There are an obvious set of applications that are just on the edge of possible, and you
won’t be able to approach them without writing optimally performant code. If that’s
your practice, you’re in the right place. But there is a much broader set of applica‐
tions that can benefit from performant code.
We often think that new technical capabilities are what drives innovation, but I’m
equally fond of capabilities that increase the accessibility of technology by orders of
magnitude. When something becomes ten times cheaper in time or compute costs,
suddenly the set of applications you can address is wider than you imagined.
The first time this principle manifested in my own work was over a decade ago, when
I was working at a social media company, and we ran an analysis over multiple tera‐
bytes of data to determine whether people clicked on more photos of cats or dogs on
social media.
It was dogs, of course. Cats just have better branding.
This was an outstandingly frivolous use of compute time and infrastructure at the
time! Gaining the ability to apply techniques that had previously been restricted to
sufficiently high-value applications, such as fraud detection, to a seemingly trivial
question opened up a new world of now-accessible possibilities. We were able to take
what we learned from these experiments and build a whole new set of products in
search and content discovery.
Foreword | xi
For an example that you might encounter today, consider a machine-learning system
that recognizes unexpected animals or people in security video footage. A sufficiently
performant system could allow you to embed that model into the camera itself,
improving privacy or, even if running in the cloud, using significantly less compute
and power—benefiting the environment and reducing your operating costs. This can
free up resources for you to look at adjacent problems, potentially building a more
valuable system.
We all desire to create systems that are effective, easy to understand, and performant.
Unfortunately, it often feels like we have to pick two (or one) out of the three! High
Performance Python is a handbook for people who want to make things that are capa‐
ble of all three.
This book stands apart from other texts on the subject in three ways. First, it’s written
for us—humans who write code. You’ll find all of the context you need to understand
why you might make certain choices. Second, Gorelick and Ozsvald do a wonderful
job of curating and explaining the necessary theory to support that context. Finally,
in this updated edition, you’ll learn the specific quirks of the most useful libraries for
implementing these approaches today.
This is one of a rare class of programming books that will change the way you think
about the practice of programming. I’ve given this book to many people who could
benefit from the additional tools it provides. The ideas that you’ll explore in its pages
will make you a better programmer, no matter what language or environment you
choose to work in.
Enjoy the adventure.
— Hilary Mason,
Data Scientist in Residence at Accel
xii | Foreword
Preface
Python is easy to learn. You’re probably here because now that your code runs cor‐
rectly, you need it to run faster. You like the fact that your code is easy to modify and
you can iterate with ideas quickly. The trade-off between easy to develop and runs as
quickly as I need is a well-understood and often-bemoaned phenomenon. There are
solutions.
Some people have serial processes that have to run faster. Others have problems that
could take advantage of multicore architectures, clusters, or graphics processing
units. Some need scalable systems that can process more or less as expediency and
funds allow, without losing reliability. Others will realize that their coding techni‐
ques, often borrowed from other languages, perhaps aren’t as natural as examples
they see from others.
In this book we will cover all of these topics, giving practical guidance for under‐
standing bottlenecks and producing faster and more scalable solutions. We also
include some war stories from those who went ahead of you, who took the knocks so
you don’t have to.
Python is well suited for rapid development, production deployments, and scalable
systems. The ecosystem is full of people who are working to make it scale on your
behalf, leaving you more time to focus on the more challenging tasks around you.
Who This Book Is For
You’ve used Python for long enough to have an idea about why certain things are
slow and to have seen technologies like Cython, numpy, and PyPy being discussed as
possible solutions. You might also have programmed with other languages and so
know that there’s more than one way to solve a performance problem.
While this book is primarily aimed at people with CPU-bound problems, we also
look at data transfer and memory-bound solutions. Typically, these problems are
faced by scientists, engineers, quants, and academics.
Preface | xiii
We also look at problems that a web developer might face, including the movement
of data and the use of just-in-time (JIT) compilers like PyPy and asynchronous I/O
for easy-win performance gains.
It might help if you have a background in C (or C++, or maybe Java), but it isn’t a
prerequisite. Python’s most common interpreter (CPython—the standard you nor‐
mally get if you type python at the command line) is written in C, and so the hooks
and libraries all expose the gory inner C machinery. There are lots of other
techniques that we cover that don’t assume any knowledge of C.
You might also have a lower-level knowledge of the CPU, memory architecture, and
data buses, but again, that’s not strictly necessary.
Who This Book Is Not For
This book is meant for intermediate to advanced Python programmers. Motivated
novice Python programmers may be able to follow along as well, but we recommend
having a solid Python foundation.
We don’t cover storage-system optimization. If you have a SQL or NoSQL bottle‐
neck, then this book probably won’t help you.
What You’ll Learn
Your authors have been working with large volumes of data, a requirement for I want
the answers faster! and a need for scalable architectures, for many years in both
industry and academia. We’ll try to impart our hard-won experience to save you
from making the mistakes that we’ve made.
At the start of each chapter, we’ll list questions that the following text should answer.
(If it doesn’t, tell us and we’ll fix it in the next revision!)
We cover the following topics:
• Background on the machinery of a computer so you know what’s happening
behind the scenes
• Lists and tuples—the subtle semantic and speed differences in these fundamental
data structures
• Dictionaries and sets—memory allocation strategies and access algorithms in
these important data structures
• Iterators—how to write in a more Pythonic way and open the door to infinite
data streams using iteration
• Pure Python approaches—how to use Python and its modules effectively
xiv | Preface
• Matrices with numpy—how to use the beloved numpy library like a beast
• Compilation and just-in-time computing—processing faster by compiling down
to machine code, making sure you’re guided by the results of profiling
• Concurrency—ways to move data efficiently
• multiprocessing—various ways to use the built-in multiprocessing library for
parallel computing and to efficiently share numpy matrices, and some costs and
benefits of interprocess communication (IPC)
• Cluster computing—convert your multiprocessing code to run on a local or
remote cluster for both research and production systems
• Using less RAM—approaches to solving large problems without buying a
humungous computer
• Lessons from the field—lessons encoded in war stories from those who took the
blows so you don’t have to
Python 3
Python 3 is the standard version of Python as of 2020, with Python 2.7 deprecated
after a 10-year migration process. If you’re still on Python 2.7, you’re doing it wrong
—many libraries are no longer supported for your line of Python, and support will
become more expensive over time. Please do the community a favor and migrate to
Python 3, and make sure that all new projects use Python 3.
In this book, we use 64-bit Python. Whilst 32-bit Python is supported, it is far less
common for scientific work. We’d expect all the libraries to work as usual, but
numeric precision, which depends on the number of bits available for counting, is
likely to change. 64-bit is dominant in this field, along with *nix environments (often
Linux or Mac). 64-bit lets you address larger amounts of RAM. *nix lets you build
applications that can be deployed and configured in well-understood ways with well-
understood behaviors.
If you’re a Windows user, you’ll have to buckle up. Most of what we show will work
just fine, but some things are OS-specific, and you’ll have to research a Windows sol‐
ution. The biggest difficulty a Windows user might face is the installation of modules:
research in sites like Stack Overflow should give you the solutions you need. If you’re
on Windows, having a virtual machine (e.g., using VirtualBox) with a running Linux
installation might help you to experiment more freely.
Windows users should definitely look at a packaged solution like those available
through Anaconda, Canopy, Python(x,y), or Sage. These same distributions will
make the lives of Linux and Mac users far simpler too.
Preface | xv
Changes from Python 2.7
If you’ve upgraded from Python 2.7, you might not be aware of a few relevant
changes:
• / meant integer division in Python 2.7, whereas it performs float division in
Python 3.
• str and unicode were used to represent text data in Python 2.7; in Python 3,
everything is a str, and these are always Unicode. For clarity, a bytes type is
used if we’re using unencoded byte sequences.
If you’re in the process of upgrading your code, two good guides are “Porting Python
2 Code to Python 3” and “Supporting Python 3: An in-depth guide”. With a distribu‐
tion like Anaconda or Canopy, you can run both Python 2 and Python 3 simultane‐
ously—this will simplify your porting.
License
This book is licensed under Creative Commons Attribution-NonCommercial-
NoDerivs 3.0.
You’re welcome to use this book for noncommercial purposes, including for
noncommercial teaching. The license allows only for complete reproductions; for
partial reproductions, please contact O’Reilly (see “How to Contact Us” on page xviii).
Please attribute the book as noted in the following section.
We negotiated that the book should have a Creative Commons license so the con‐
tents could spread further around the world. We’d be quite happy to receive a beer if
this decision has helped you. We suspect that the O’Reilly staff would feel similarly
about the beer.
How to Make an Attribution
The Creative Commons license requires that you attribute your use of a part of this
book. Attribution just means that you should write something that someone else can
follow to find this book. The following would be sensible: “High Performance Python,
2nd ed., by Micha Gorelick and Ian Ozsvald (O’Reilly). Copyright 2020 Micha Gore‐
lick and Ian Ozsvald, 978-1-492-05502-0.”
xvi | Preface
Errata and Feedback
We encourage you to review this book on public sites like Amazon—please help oth‐
ers understand if they would benefit from this book! You can also email us at
feedback@highperformancepython.com.
We’re particularly keen to hear about errors in the book, successful use cases where
the book has helped you, and high performance techniques that we should cover in
the next edition. You can access the web page for this book at https://oreil.ly/high-
performance-python-2e.
Complaints are welcomed through the instant-complaint-transmission-service
> /dev/null.
Conventions Used in This Book
The following typographical conventions are used in this book:
Italic
Indicates new terms, URLs, email addresses, filenames, and file extensions.
Constant width
Used for program listings, as well as within paragraphs to refer to program ele‐
ments such as variable or function names, databases, datatypes, environment
variables, statements, and keywords.
Constant width bold
Shows commands or other text that should be typed literally by the user.
Constant width italic
Shows text that should be replaced with user-supplied values or by values deter‐
mined by context.
This element signifies a tip, suggestion, or critical thinking ques‐
tion.
This element signifies a general note.
Preface | xvii
This element indicates a warning or caution.
Using Code Examples
Supplemental material (code examples, exercises, etc.) is available for download at
https://github.com/mynameisfiber/high_performance_python_2e.
If you have a technical question or a problem using the code examples, please send
email to bookquestions@oreilly.com.
This book is here to help you get your job done. In general, if example code is offered
with this book, you may use it in your programs and documentation. You do not
need to contact us for permission unless you’re reproducing a significant portion of
the code. For example, writing a program that uses several chunks of code from this
book does not require permission. Selling or distributing examples from O’Reilly
books does require permission. Answering a question by citing this book and quoting
example code does not require permission. Incorporating a significant amount of
example code from this book into your product’s documentation does require
permission.
If you feel your use of code examples falls outside fair use or the permission given
above, feel free to contact us at permissions@oreilly.com.
O’Reilly Online Learning
For more than 40 years, O’Reilly Media has provided technol‐
ogy and business training, knowledge, and insight to help
companies succeed.
Our unique network of experts and innovators share their knowledge and expertise
through books, articles, and our online learning platform. O’Reilly’s online learning
platform gives you on-demand access to live training courses, in-depth learning
paths, interactive coding environments, and a vast collection of text and video from
O’Reilly and 200+ other publishers. For more information, visit http://oreilly.com.
How to Contact Us
Please address comments and questions concerning this book to the publisher:
xviii | Preface
O’Reilly Media, Inc.
1005 Gravenstein Highway North
Sebastopol, CA 95472
800-998-9938 (in the United States or Canada)
707-829-0515 (international or local)
707-829-0104 (fax)
Email bookquestions@oreilly.com to comment or ask technical questions about this
book.
For news and more information about our books and courses, see our website at
http://oreilly.com.
Find us on Facebook: http://facebook.com/oreilly
Follow us on Twitter: http://twitter.com/oreillymedia
Watch us on YouTube: http://youtube.com/oreillymedia
Acknowledgments
Hilary Mason wrote our foreword—thanks for composing such a wonderful opening
narrative for our book. Giles Weaver and Dimitri Denisjonok provided invaluable
technical feedback on this edition; great work, chaps.
Thanks to Patrick Cooper, Kyran Dale, Dan Foreman-Mackey, Calvin Giles, Brian
Granger, Jamie Matthews, John Montgomery, Christian Schou Oxvig, Matt “snakes”
Reiferson, Balthazar Rouberol, Michael Skirpan, Luke Underwood, Jake Vanderplas,
and William Winter for invaluable feedback and contributions.
Ian thanks his wife, Emily, for letting him disappear for another eight months to
write this second edition (thankfully, she’s terribly understanding). Ian apologizes to
his dog for sitting and writing rather than walking in the woods quite as much as
she’d have liked.
Micha thanks Marion and the rest of his friends and family for being so patient while
he learned to write.
O’Reilly editors are rather lovely to work with; do strongly consider talking to them if
you want to write your own book.
Our contributors to the “Lessons from the Field” chapter very kindly shared their
time and hard-won lessons. We give thanks to Soledad Galli, Linda Uruchurtu,
Vanentin Haenel, and Vincent D. Warmerdam for this edition and to Ben Jackson,
Radim Řehůřek, Sebastjan Trepca, Alex Kelly, Marko Tasic, and Andrew Godwin for
their time and effort during the previous edition.
Preface | xix
CHAPTER 1
Understanding Performant Python
Questions You’ll Be Able to Answer After This Chapter
• What are the elements of a computer’s architecture?
• What are some common alternate computer architectures?
• How does Python abstract the underlying computer architecture?
• What are some of the hurdles to making performant Python code?
• What strategies can help you become a highly performant programmer?
Programming computers can be thought of as moving bits of data and transforming
them in special ways to achieve a particular result. However, these actions have a time
cost. Consequently, high performance programming can be thought of as the act of
minimizing these operations either by reducing the overhead (i.e., writing more effi‐
cient code) or by changing the way that we do these operations to make each one
more meaningful (i.e., finding a more suitable algorithm).
Let’s focus on reducing the overhead in code in order to gain more insight into the
actual hardware on which we are moving these bits. This may seem like a futile exer‐
cise, since Python works quite hard to abstract away direct interactions with the
hardware. However, by understanding both the best way that bits can be moved in
the real hardware and the ways that Python’s abstractions force your bits to move,
you can make progress toward writing high performance programs in Python.
1
The Fundamental Computer System
The underlying components that make up a computer can be simplified into three
basic parts: the computing units, the memory units, and the connections between
them. In addition, each of these units has different properties that we can use to
understand them. The computational unit has the property of how many computa‐
tions it can do per second, the memory unit has the properties of how much data it
can hold and how fast we can read from and write to it, and finally, the connections
have the property of how fast they can move data from one place to another.
Using these building blocks, we can talk about a standard workstation at multiple lev‐
els of sophistication. For example, the standard workstation can be thought of as hav‐
ing a central processing unit (CPU) as the computational unit, connected to both the
random access memory (RAM) and the hard drive as two separate memory units
(each having different capacities and read/write speeds), and finally a bus that pro‐
vides the connections between all of these parts. However, we can also go into more
detail and see that the CPU itself has several memory units in it: the L1, L2, and
sometimes even the L3 and L4 cache, which have small capacities but very fast speeds
(from several kilobytes to a dozen megabytes). Furthermore, new computer architec‐
tures generally come with new configurations (for example, Intel’s SkyLake CPUs
replaced the frontside bus with the Intel Ultra Path Interconnect and restructured
many connections). Finally, in both of these approximations of a workstation we
have neglected the network connection, which is effectively a very slow connection to
potentially many other computing and memory units!
To help untangle these various intricacies, let’s go over a brief description of these
fundamental blocks.
Computing Units
The computing unit of a computer is the centerpiece of its usefulness—it provides the
ability to transform any bits it receives into other bits or to change the state of the
current process. CPUs are the most commonly used computing unit; however,
graphics processing units (GPUs) are gaining popularity as auxiliary computing
units. They were originally used to speed up computer graphics but are becoming
more applicable for numerical applications and are useful thanks to their intrinsically
parallel nature, which allows many calculations to happen simultaneously. Regardless
of its type, a computing unit takes in a series of bits (for example, bits representing
numbers) and outputs another set of bits (for example, bits representing the sum of
those numbers). In addition to the basic arithmetic operations on integers and real
numbers and bitwise operations on binary numbers, some computing units also pro‐
vide very specialized operations, such as the “fused multiply add” operation, which
takes in three numbers, A, B, and C, and returns the value A * B + C.
2 | Chapter 1: Understanding Performant Python
1 Not to be confused with interprocess communication, which shares the same acronym—we’ll look at that
topic in Chapter 9.
The main properties of interest in a computing unit are the number of operations it
can do in one cycle and the number of cycles it can do in one second. The first value
is measured by its instructions per cycle (IPC),1
while the latter value is measured by
its clock speed. These two measures are always competing with each other when new
computing units are being made. For example, the Intel Core series has a very high
IPC but a lower clock speed, while the Pentium 4 chip has the reverse. GPUs, on the
other hand, have a very high IPC and clock speed, but they suffer from other prob‐
lems like the slow communications that we discuss in “Communications Layers” on
page 8.
Furthermore, although increasing clock speed almost immediately speeds up all pro‐
grams running on that computational unit (because they are able to do more calcula‐
tions per second), having a higher IPC can also drastically affect computing by
changing the level of vectorization that is possible. Vectorization occurs when a CPU
is provided with multiple pieces of data at a time and is able to operate on all of them
at once. This sort of CPU instruction is known as single instruction, multiple data
(SIMD).
In general, computing units have advanced quite slowly over the past decade (see
Figure 1-1). Clock speeds and IPC have both been stagnant because of the physical
limitations of making transistors smaller and smaller. As a result, chip manufacturers
have been relying on other methods to gain more speed, including simultaneous mul‐
tithreading (where multiple threads can run at once), more clever out-of-order exe‐
cution, and multicore architectures.
Hyperthreading presents a virtual second CPU to the host operating system (OS),
and clever hardware logic tries to interleave two threads of instructions into the exe‐
cution units on a single CPU. When successful, gains of up to 30% over a single
thread can be achieved. Typically, this works well when the units of work across both
threads use different types of execution units—for example, one performs floating-
point operations and the other performs integer operations.
Out-of-order execution enables a compiler to spot that some parts of a linear pro‐
gram sequence do not depend on the results of a previous piece of work, and there‐
fore that both pieces of work could occur in any order or at the same time. As long as
sequential results are presented at the right time, the program continues to execute
correctly, even though pieces of work are computed out of their programmed order.
This enables some instructions to execute when others might be blocked (e.g., wait‐
ing for a memory access), allowing greater overall utilization of the available
resources.
The Fundamental Computer System | 3
Finally, and most important for the higher-level programmer, there is the prevalence
of multicore architectures. These architectures include multiple CPUs within the
same unit, which increases the total capability without running into barriers to mak‐
ing each individual unit faster. This is why it is currently hard to find any machine
with fewer than two cores—in this case, the computer has two physical computing
units that are connected to each other. While this increases the total number of oper‐
ations that can be done per second, it can make writing code more difficult!
Figure 1-1. Clock speed of CPUs over time (from CPU DB)
Simply adding more cores to a CPU does not always speed up a program’s execution
time. This is because of something known as Amdahl’s law. Simply stated, Amdahl’s
law is this: if a program designed to run on multiple cores has some subroutines that
must run on one core, this will be the limitation for the maximum speedup that can
be achieved by allocating more cores.
For example, if we had a survey we wanted one hundred people to fill out, and that
survey took 1 minute to complete, we could complete this task in 100 minutes if we
had one person asking the questions (i.e., this person goes to participant 1, asks the
questions, waits for the responses, and then moves to participant 2). This method of
having one person asking the questions and waiting for responses is similar to a serial
process. In serial processes, we have operations being satisfied one at a time, each one
waiting for the previous operation to complete.
However, we could perform the survey in parallel if we had two people asking the
questions, which would let us finish the process in only 50 minutes. This can be done
4 | Chapter 1: Understanding Performant Python
because each individual person asking the questions does not need to know anything
about the other person asking questions. As a result, the task can easily be split up
without having any dependency between the question askers.
Adding more people asking the questions will give us more speedups, until we have
one hundred people asking questions. At this point, the process would take 1 minute
and would be limited simply by the time it takes a participant to answer questions.
Adding more people asking questions will not result in any further speedups, because
these extra people will have no tasks to perform—all the participants are already
being asked questions! At this point, the only way to reduce the overall time to run
the survey is to reduce the amount of time it takes for an individual survey, the serial
portion of the problem, to complete. Similarly, with CPUs, we can add more cores
that can perform various chunks of the computation as necessary until we reach a
point where the bottleneck is the time it takes for a specific core to finish its task. In
other words, the bottleneck in any parallel calculation is always the smaller serial
tasks that are being spread out.
Furthermore, a major hurdle with utilizing multiple cores in Python is Python’s use
of a global interpreter lock (GIL). The GIL makes sure that a Python process can run
only one instruction at a time, regardless of the number of cores it is currently using.
This means that even though some Python code has access to multiple cores at a
time, only one core is running a Python instruction at any given time. Using the pre‐
vious example of a survey, this would mean that even if we had 100 question askers,
only one person could ask a question and listen to a response at a time. This effec‐
tively removes any sort of benefit from having multiple question askers! While this
may seem like quite a hurdle, especially if the current trend in computing is to have
multiple computing units rather than having faster ones, this problem can be avoided
by using other standard library tools, like multiprocessing (Chapter 9), technologies
like numpy or numexpr (Chapter 6), Cython (Chapter 7), or distributed models of
computing (Chapter 10).
Python 3.2 also saw a major rewrite of the GIL, which made the
system much more nimble, alleviating many of the concerns
around the system for single-thread performance. Although it still
locks Python into running only one instruction at a time, the GIL
now does better at switching between those instructions and doing
so with less overhead.
Memory Units
Memory units in computers are used to store bits. These could be bits representing
variables in your program or bits representing the pixels of an image. Thus, the
abstraction of a memory unit applies to the registers in your motherboard as well as
your RAM and hard drive. The one major difference between all of these types of
The Fundamental Computer System | 5
2 Speeds in this section are from https://oreil.ly/pToi7.
memory units is the speed at which they can read/write data. To make things more
complicated, the read/write speed is heavily dependent on the way that data is being
read.
For example, most memory units perform much better when they read one large
chunk of data as opposed to many small chunks (this is referred to as sequential read
versus random data). If the data in these memory units is thought of as pages in a
large book, this means that most memory units have better read/write speeds when
going through the book page by page rather than constantly flipping from one ran‐
dom page to another. While this fact is generally true across all memory units, the
amount that this affects each type is drastically different.
In addition to the read/write speeds, memory units also have latency, which can be
characterized as the time it takes the device to find the data that is being used. For a
spinning hard drive, this latency can be high because the disk needs to physically spin
up to speed and the read head must move to the right position. On the other hand,
for RAM, this latency can be quite small because everything is solid state. Here is a
short description of the various memory units that are commonly found inside a
standard workstation, in order of read/write speeds:2
Spinning hard drive
Long-term storage that persists even when the computer is shut down. Generally
has slow read/write speeds because the disk must be physically spun and moved.
Degraded performance with random access patterns but very large capacity (10
terabyte range).
Solid-state hard drive
Similar to a spinning hard drive, with faster read/write speeds but smaller
capacity (1 terabyte range).
RAM
Used to store application code and data (such as any variables being used). Has
fast read/write characteristics and performs well with random access patterns,
but is generally limited in capacity (64 gigabyte range).
L1/L2 cache
Extremely fast read/write speeds. Data going to the CPU must go through here.
Very small capacity (megabytes range).
Figure 1-2 gives a graphic representation of the differences between these types of
memory units by looking at the characteristics of currently available consumer
hardware.
6 | Chapter 1: Understanding Performant Python
A clearly visible trend is that read/write speeds and capacity are inversely propor‐
tional—as we try to increase speed, capacity gets reduced. Because of this, many sys‐
tems implement a tiered approach to memory: data starts in its full state in the hard
drive, part of it moves to RAM, and then a much smaller subset moves to the L1/L2
cache. This method of tiering enables programs to keep memory in different places
depending on access speed requirements. When trying to optimize the memory pat‐
terns of a program, we are simply optimizing which data is placed where, how it is
laid out (in order to increase the number of sequential reads), and how many times it
is moved among the various locations. In addition, methods such as asynchronous
I/O and preemptive caching provide ways to make sure that data is always where it
needs to be without having to waste computing time—most of these processes can
happen independently, while other calculations are being performed!
Figure 1-2. Characteristic values for different types of memory units (values from
February 2014)
The Fundamental Computer System | 7
Discovering Diverse Content Through
Random Scribd Documents
Everything that I read with Harry, or that I talk over with him, has
new meaning for me, or a new force.
Why are we so careful to avoid pain? If it was a necessary part of
the highest mortal experience, how can we ask that it may be left
out from ours? And yet, on every new occasion, we strive to put
from us the offered cross. Even while we say, "Thy will be done!" an
inward hope entreats that will to be merciful. Such remonstrances
with myself rose in me as I read. They did not prevent me from
feeling a thrill of dread as this warning passed over my lips:—"Who
shall say how soon God may draw us from our easy speculations and
theories of suffering, to the practical experience of it? Who can tell
how soon we may be called to the fiery trial?" I turned involuntarily
to Harry. He, too, had heard a summons in these words. I read in his
eyes the answer that came from his steady breast,—"My Father, I
am here!" I felt my spirit lifted with the closing words,—"If we suffer
with him, we shall also reign with him"; but there was no change in
Harry's clear, prepared look. I have never known a faith so implicit as
his. He does not ask after threats or promises; he only listens for
commands.
When the services were over, Hans came forward to say good-bye to
the Doctor and Harry. He took a hand of each, and stood looking
from one to the other.
"We cannot spare you, Harry Dudley. We shall miss you, Doctor.
Harry, when you are ready to set up your farm, come and take a
look round you here again. We are good people, and love you. There
will be land near in the market before long. Sooner should you have
it than old Rasey. Think of it; we can talk things over, evenings."
"You shall have your turn," he said to his boys, who were waiting,
one on either side of him. "I am an old man, and leave-taking comes
hard. Youth has many chances more."
He gave his benediction, repeated a little rhyming German couplet,—
a charm, perhaps, for a good journey,—and then turned away
sturdily, went slowly out of the door and down the steps, leaving
Karl and Fritz to say their words of farewell. Karl spoke for both.
What Fritz had in his heart to say he could not utter, for the tears
would have come with it.
At a quarter before twelve Harry brought down the russet knapsack,
—brought down the little flower-press,—brought down the long
umbrella.
He transferred from the over-full knapsack to his own some
packages of flowers. The flower-press would not enter either
knapsack. The Doctor had it strapped on outside his. I watched
these little arrangements, glad of the time they took. Harry helped
the Doctor on with his pack. I would have done the same for Harry,
but he was too quick for me. I adjusted the strap from which the
green tin case hung, that I might do something for him.
Doctor Borrow took a serious leave of my mother,—for this, at least,
was a final one. But Harry would not have it so. The tears were
gathering in her eyes. "You will see us again," he said, confidently.
The Doctor shook his head. "You have made us too happy here for
us not to wish that it might be so."
But my mother accepted Harry's assurance.
They looked round for Tabitha. She appeared from my mother's
room, the door of which had been a little open. Both thanked her
cordially for her kind cares. She gave them her good wishes,
affectionately and solemnly, and disappeared again.
"I shall not bid you good-bye," said the Doctor, yet taking my hand.
"Only till the nineteenth," said Harry, clasping it as soon as the
Doctor relinquished it. "Till the eighteenth," I mean; "till the
eighteenth," he repeated, urgently.
"Till the eighteenth," I answered.
The Doctor mounted the blue spectacles. This was the last act of
preparation. The minute-hand was close upon the appointed
moment.
At the first stroke of twelve, they were on their way. I followed,
slowly, as if the reluctance of my steps could hold back theirs. The
gate closed behind them. The Doctor took at once his travelling gait
and trudged straight on; but Harry turned and gave a glance to the
house, to the barn, to the little patch of flowers,—to all the objects
with which the week had made him familiar. Then his look fell upon
me, who was waiting for it. He searched my face intently for an
instant, and then, with a smile which made light of all but happy
presentiments, waved me adieu, and hastened on to overtake the
Doctor.
I was glad it was not a working-day,—glad that I could go in and sit
down by my mother, to talk over with her, or, silent, to think over
with her, the scenes which had animated our little room, and which
were still to animate it. Harry's parting look stayed with me. I felt all
my gain, and had no more sense of loss. Can we ever really lose
what we have ever really possessed?
Evening.
I have been over to Blanty's. I should have gone yesterday, but it
rained heavily from early morning until after dark. Such days I
consider yours. I had been anxious about Blanty since Sunday, and
not altogether without reason. He has had a threatening of fever. I
hope it will prove a false alarm. I found him sitting at his door,
already better,—but still a good deal cast down, for he was never ill
in his life before. He had been wishing for me, and would have sent
to me, if I had not gone. He could hardly let me come away, but
pressed me to stay one hour longer, one half hour, one quarter. But I
had some things to attend to at home, and, as he did not really
need me, I bade him good-bye resolutely, promising to go to him
again next Monday. I cannot well go sooner.
If I had stayed, I should have missed a visit from Frederic Harvey.
When I came within sight of our gate, on the way back, a horseman
was waiting at it, looking up the road, as if watching for me. He
darted forward, on my appearance,—stopped short, when close
beside me,—dismounted, and greeted me with a warmth which I
blamed myself for finding it hard to return. He did not blame me,
apparently. Perhaps he ascribes the want he may feel in my manner
to New-England reserve; or perhaps he feels no want. He is so
assured of the value of his regard, that he takes full reciprocity for
granted. The docile horse, at a sign, turned and walked along beside
us to the gate, followed us along the path to the house, and took his
quiet stand before the door when we went in.
Frederic Harvey, having paid his respects to my mother, seated
himself in the great arm-chair, which now seems to be always
claiming the Doctor, and which this new, slender occupant filled very
inadequately.
"I stayed in New York three weeks too long," he exclaimed, after
looking about him a little—for traces of Harry, it seemed. "Time goes
so fast there! But I thought, from one of my sister's letters, that
Dudley was to go back to World's End after he left you. Is he
changed? Oh, but you cannot tell. You never knew him till now. I
need not have asked, at any rate. He is not one to change. While I
knew him, he was only more himself with every year."
"It is two years since you met, is it not?"
"Yes; but what are two years to men who were children together?
We shall take things up just where we laid them down. Ours is the
older friendship. I shall always have the advantage of you there. But
you and he must have got along very well together. Your notions
agree with his better than mine do. It does not matter. Friendship
goes by fate, I believe. He may hold what opinions he likes, for me;
and so may you."
"I believe that on some important subjects my opinions differ very
much from yours."—I am determined to stand square with Frederic
Harvey.
"In regard to our institutions, you mean? I know, that, spoken or
unspoken, hatred of them is carried in the heart of every New-
Englander. It is sometimes suppressed through politeness or from
interest, but I never saw a Northerner who was good for anything, in
whom it did not break out on the first provocation. I like as well to
have it fairly understood in the outset. I have had a letter from Harry
in answer to one of mine. It is explicit on this point."
I had no doubt it was very explicit. Frederic's eye meeting mine, he
caught my thought, and we had a good laugh together, which made
us better friends.
"The Northerners are brought up in their set of prejudices, as we in
ours. I can judge of the force of theirs by that of my own. I only
wish there was the same unanimity among us. We are a house
divided against itself."
And Frederic's face darkened,—perhaps with the recollection of the
rupture of old ties in Shaler's case,—or rather, as it seemed, with the
rankling of some later, nearer pain. He turned quickly away from the
intrusive thought, whatever it was. He does not like the unpleasant
side of things.
"At any rate, because Harry Dudley and I are to be adverse, it does
not follow that we are to be estranged. I cannot forget our school-
days,—our walks on the boulevards and the quays,—our rides in the
Bois,—our journeys together, when we were like brothers. I was
never so happy as in those days, when I had not a care or a duty in
the world."
He had the air, with his twenty-one years, of a weary man-of-the-
world. There was no affectation in it. Unless report have done him
injustice, the last two years have put a gulf between him and that
time.
I reminded him of the conversation between him and his sister, in
which they spoke of Harry Dudley before I knew who Harry Dudley
was. He remembered it, and returned very readily to the subject of
it. He related many incidents of the tour in Brittany, and spoke
warmly of the pleasure of travelling with a companion who is alive to
everything of interest in every sort. He said his travels in Germany,
and even in Italy, had hardly left with him so lively and enduring
impressions as this little journey into Brittany; for there he had gone
to the heart of things.
"I must see him again. We must meet once more as we used to
meet. We must have one good clasp of the hand; we must, at least,
say a kind good-bye to the old friendship. If, hereafter, we find
ourselves opposed in public life, I shall deal him the worst I can, but
with openness and loyalty like his own, and doing him more justice
in my heart, perhaps, than he will do me."
Frederic Harvey inquired anxiously where Harry was to be found,
and I was obliged to tell him of our intended meeting. I was afraid
he would propose to go with me. He was on the point of doing so,
but refrained, seeing that I was not expecting such a suggestion.
We could easily have arranged to meet at Quickster, which is about
the same distance from him that it is from me. But a ride of twenty
miles, most of them slow ones, beside a man with whom you are not
in full sympathy, is a trial. I did not feel called upon to undergo it for
him. When he took leave of me, he again seemed about to propose
something, and I felt it was this plan which was so natural; but he
was again withheld, by pride or by delicacy. Either feeling I could
sympathize with, and I was more touched by this reserve than by all
his friendly advances; but I hardened my heart. He mounted his
horse. I saw him go slowly down the path to the road, stoop from
the saddle to open the gate,—pass out. And then I was seized with
sudden compunction. I heard the slow step of his horse, receding as
if reluctantly, and ready to be checked at a hint. I ran to the gate.
Frederic was just turning away, as if he had been looking back,
expecting to see me; but in the same instant he gave an intimation
to his horse, and was out of the reach of my repentance.
"I liked him." With Harry these words mean a great deal. Could
Harry ever have liked him, if he had not been worthy to be liked?
How sad his look was, when he spoke of his happy boyish days!—
happier than these only because they were blameless. Was not this
regret itself an earnest of the power of return? He had good blood in
him. He is Charles Shaler's cousin. He has a weak, shallow mother,—
a father whose good qualities and whose faults are overlaid with the
same worldly varnish impartially. He feels the need of other
influences, and clings to Harry. He comes to me instinctively seeking
something he has not in his home. My mother has always judged
him more kindly than I have. If he had been a poor outcast child, I
should have felt his coming to me so frankly and so persistently to
be a sign I was to do something for him. Is there a greater need
than that of sympathy and honest counsel? I have been selfish, but
this pain is punishment enough. I feel a remorse surely out of
proportion to my sin. I do not prevent his going to meet Harry by
not asking him to go with me. He is not one to give up his wish; and
in this case there is no reason that he should. He will arrive; I am
sure of it. And I will atone, at least in part. I will ask him to join me
on the ride home.
Old Jasper has told me stories of Frederic Harvey's good-
heartedness in childhood: tells them to me, indeed, every time he
sees me. I remember one in particular, of the pretty little boy in his
foreign dress, and speaking his foreign language, carrying his own
breakfast one morning to the cabin where the old man lay sick; and
another of his taking away part of her load from a feeble woman;
and another of his falling on a driver and wresting from him the whip
with which he was lashing a fainting boy. But Jasper has only these
early stories to tell of him; and what different ones are current now!
In dear old New England the child is father of the man. There the
lovely infancy is the sure promise of the noble maturity. But where
justice is illegal! where mercy is a criminal indulgence! where youth
is disciplined to selfishness, and the man's first duty is to deny
himself his virtues! If the nephew of Augustus had lived, would he
indeed have been Marcellus? Heu pietas! Heu prisca fides!—these
might have been mourned, though Octavia had not wept her son.
Thursday, April 18, 1844.
It is thirty-five miles to Omocqua by the common road through
Metapora and Tenpinville; but I shall save myself five, going across
fields and through wood-paths, and coming out at Quickster. You left
the Omocqua road there, and took that to Quarleston. I shall stop
half an hour at Quickster to rest my horse and have a little talk with
Barton. I mean to allow myself ample time for the journey, that
Brownie may take it easily and yet bring me to Omocqua in season
for a stroll about the neighborhood with the Doctor and Harry before
nightfall. Some miles of my way are difficult with tree-stumps and
brush; a part of it is sandy; the last third is hilly. I have never been
farther on that road than Ossian, about three miles beyond
Quickster; but the country between Ossian and Omocqua is, I know,
very much like that between Quarleston and Cyclops, which you
found so beautiful and so tiresome.
I do not mean that my parting with Harry shall be a sad one. After
that day at Omocqua, I shall not meet his smile,—his hand will not
clasp mine again; but he will leave with me something of himself
which will not go from me. His courage, the energy of his
straightforward will, shall still nerve and brace me, though his cordial
voice may never again convey their influence to my heart. Wherever
he is, I shall know we are thinking, feeling together, and working
together; for I shall surely do what he asks of me: that he thinks it
worth doing is enough.
And Dr. Borrow does not leave me what he found me. It was with a
continual surprise that I learned how much there is of interest and
variety in our uniform neighborhood for a man who knows the
meaning of what he sees. How many things are full of suggestion
now that were mute before! He has given me glimpses of
undreamed-of pleasures. A practical man, following him in his walks,
and gathering up the hints he lets fall, might turn them to great real
use.
What a part the Doctor and such as he, disciples and interpreters of
Nature, would have in the world, how warmly they would be
welcomed everywhere, if these were only times in which men could
live as they were meant to live, happy and diligent, cherishing Earth
and adorning her, receiving her daily needful gifts, and from time to
time coming upon precious ones, which she, fond and wise mother,
has kept back for the surprise of some hour of minuter search or
bolder divination!
But now, how can we be at ease to enjoy our own lot, however
pleasantly it may have been cast for us, or to occupy ourselves with
material cares or works, even the most worthy and the most
rational?
We are taught to pray, "Thy kingdom come," before we ask for our
daily bread.
To pray for what we do not at the same time strive for, is it not an
impiety?
Dr. Borrow says that Harry is out of place in our time. I should rather
say that it is he himself who is here a century, or perhaps only a
half-century, too soon. Our first need now is of men clear-sighted to
moral truths, and intrepid to announce and maintain them.
It was through the consciousness, not yet lost, of eternal principles,
that primitive poetry made Themis the mother of the gracious Hours,
—those beneficent guardians, bringers of good gifts, promoters and
rewarders of man's happy labor. When Justice returns to make her
reign on earth, with her come back her lovely daughters, and all the
beautiful attendant train.
When that time arrives, the Doctor will have found his place, and
Harry will not have lost his.
Perhaps I shall not come back until Saturday. According to their plan,
Dr. Borrow and Harry are to leave Omocqua again to-morrow
afternoon; but I shall try to persuade them to remain until the next
morning. While they stay, I shall stay. When they go, Brownie and I
take our homeward road. In any case, I will write to you Friday
night, and send off my budget on Saturday without fail.
To-day has not given me anything to tell of it yet, except that it has
opened as it should, fresh and cloudless. In five hours I shall be on
the road.
My paper is blistered and the writing blurred with wet drops. It is
only that some freshly gathered flowers on my table have let fall
their dew upon the page. You, with the trace of mysticism that lurks
in your man of the world's heart, would be drawing unfavorable
auguries. I am too happy to accept any to-day. If fancy will sport
with this accident, let it feign that these morning tears are of
sympathy, but not of compassion; that they fall, not to dim my
hopes, but to hallow them.
Evening.
"In five hours I shall be on the road." So I wrote at six o'clock. I
wrote too confidently.
At eleven I had mounted my horse, had sent my last good-bye
through the open window, and had caught the last soft answer from
within. I lingered yet an instant, held by those links of tenderness
and solicitude that bind to home and make the moment of parting
for any unusual absence, even though a pleasant and desired one, a
moment of effort. A heavy, dragging step, which I almost knew
before I saw the lounging figure of Phil Phinn, warned me of a
different delay. I watched his slow approach with a resignation which
had still a little hope in it; but when he at last stood beside me and
began his ingratiating preamble, I felt my sentence confirmed. His
woe-begone face, his quivering voice, announced the suppliant
before he reached the recital of his wrongs; while the utter self-
abandonment of his attitude conveyed renunciation of all cares and
responsibilities in favor of his elected patron. I will not give you the
details of the difficulty of to-day,—an absurd and paltry one, yet
capable of serious consequences to him. I obeyed instinctively the
old-fashioned New-England principle I was brought up in, which
requires us to postpone the desire of the moment to its demands.
Sadly I led my horse to the stable, took off the saddle and put him
up. "I cannot be back until two," I thought, "perhaps not before
three. I shall lose our walk and our sunset; but even if it is as late as
four, I will still go." I ran into the house to say a word of explanation
to my mother; but she had heard and understood. She gave me a
look of sympathy, and I did not wait for more.
I set out resolutely in a direction opposite to that in which my own
road lay. Phil Phinn followed, already raised to complacency, though
not to energy. I outwalked him continually, and was obliged to stop
and wait for him to come up. He plainly thought my haste
unseasonable, and did not disguise that he was incommoded by the
sun and the mud. It was a tedious way, a long five miles for him and
for me.
We arrived at last at the house of his adversary, who, having,
besides the advantage of being in a superior position, also that of
justice on his side, could the more easily give way. I should soon
have come to an understanding with him, if my client, while leaving
me the whole responsibility of his case, had not found himself
unable to resign its management: he must lend me the aid of his
argumentative and persuasive gifts. After some hours of wrangling
and pleading, the matter was accommodated, and Phil Phinn,
without a care in the world, or the apprehension of ever having one
again, sauntered away toward his home. I set off for mine, already
doubtful of myself, remembering that I was not the only
disappointed one.
When I reached home, it was half-past six o'clock. I felt strongly
impelled to go, even then. My mother did not offer any objection,
but her look showed so plainly the anxiety the thought of a night-
ride caused her, that I gave it up without a word. I could not,
indeed, have arrived at Omocqua before midnight, and Harry would
long have done expecting me.
I am not as well satisfied with myself as I ought to be, having made
such a sacrifice to duty. I begin to ask myself, Was it made to duty?
After all, a little suspense would have done Phil Phinn good,—if
anything can do him good. And are not the claims of friendship
paramount to all other? Harry will be pained by needless anxiety.
Can he believe that I would, without grave cause, lose any of the
time we might yet have together? But a few hours will set all right.
Friday Night, April 19.
I am at home again. I take out the package which has been waiting
for the day at Omocqua. Hoarding is always imprudence. If these
letters of last week had gone on their day, they would have been
faithful messengers. Now they go to tell you of a happiness which
already is not mine,—of hopes and plans that you can never share.
Are these last pages yesterday's? A lifetime is between me and
them. The book I pushed aside to write them lies there open,
waiting to be recalled. Had it an interest for me only yesterday? The
flowers on my table still hold their frail, transient beauty. No longer
ago than when I gathered them, I could take pleasure in flowers!
I sit here and go through the history of these last two days,
retracing every minutest incident. I begin again. I make some one
little circumstance different, and with it all is changed. I pass into a
happy dream; I find myself smiling. And then I remember that I
cannot smile!
I was to write to you to-night. I should have written, if I had not
promised. I must spend these hours with you. Every object here is
so full of pain! Everything is so exactly as it was; and yet nothing
can ever be as it was to me again!
It seemed last evening that I suffered more from my disappointment
than was reasonable. I wished for sleep to shorten the hours of
waiting. But troubled dreams lengthened them instead. I was up at
three; at four I was on the road. I had an hour over fields and
cleared land; then came some miles through the woods. The forest-
ride had not its usual charm. I was still haunted by the failure of
yesterday. I could not bear the thought of being misjudged by Harry,
even for a moment. I longed to be with him and explain. But would
he find me absolved? I was glad to come out into light and
cheerfulness at Quickster. It was six o'clock when I stood before the
door of the Rapid Run. Barton came down to me, drew out his
pocket-book, and took from it a folded paper.
"Here is something of yours."
I opened it and found written in pencil,—"Jackson House,
Omocqua." The sight of that frank handwriting dispelled every
doubt.
"When was he here?"
"He came in a little before one yesterday. He asked if you had been
along. I thought not; you would have given me a call. He stayed
round here about an hour, waiting for you. I told him that you might
have struck the road farther down,—at Ossian, perhaps. He took a
horse of me, knowing you would ride."
"He was alone?"
"Yes. He told me Dr. Borrow was at Rentree; was to join him at
Omocqua this morning, though."
In half an hour we were on our way again. I was eager still, but no
longer impatient. There was no uncertainty in my mind now. Harry
was at Omocqua. He was expecting me. As to blaming me, he had
never thought of it. He would have imagined for me some better
excuse than I had to give. Or rather, it had never occurred to him
that I could need excuse. I should find him at the door on the
lookout for me. His hand would be in mine before I could dismount.
In the mean while the miles between us diminished rapidly. My
horse enjoyed, as I did, every step of the happy road. His prompt,
elastic tread showed it, and the alert ears which seemed not
watchful against danger, but vigilant to catch all the sweet and
animating sounds that cheered us forward.
Three miles from Quickster we came on the intended town of
Ossian. I stopped a moment. Harry had probably lingered here
yesterday, watching to see me emerge from that dusky wood-path.
He had found no one to speak to. One inhabitant outstayed the rest
a year; but he has now been long gone, and his house is falling in.
Beyond Ossian the road was new to me. For about three miles it is
good. Then the country becomes uneven, and soon after very hilly.
It was slower work here; but Brownie and I took it pleasantly.
"How far is it to Omocqua?" I asked, as he was passing me, a man
whom I had watched painfully descending in his little wagon the hill
I was about to climb.
He drew up at once.
"Omocqua? You are for Omocqua? An hour, or a little more; though I
am a good hour and a half from there. They had something of a fuss
down there last night, perhaps you know."
"What about?"
"Well, a man from Tenpinville met a runaway boy of his who had
been hiding round there. The fellow ran; his master hailed him, and
when he wouldn't stop, out with a pistol and shot him flat."
"What was the man's name?"
"If I heard, I've lost it. I put up just outside the town. If I'd gone in
to hear the talk, I might have got mixed up; and I'd no call."
The hour was a long one. I hardly wished it shorter, yet I tried to
hasten. I urged my horse; but mastery is of the spirit, not of the
hand or will. He had obeyed so well the unconscious impulse! and
now, though he started forward under the spur of an inciting word,
he soon forgot it, and mounted the slow hills and descended them
again with drudging step and listless ears.
What a meeting! what a topic for the nineteenth of April! I imagined
Harry's grief, his shame, his concentrated indignation. I remembered
the flash of his eye, the flush of his cheek, when Dr. Borrow was
telling of the approach of the slave-coffle from which they had
rescued Orphy. And with this a keen apprehension seized me. Would
Harry have been able to repress his remonstrance, his reprobation?
The common man I had just met had not trusted the acquired
prudence of half a century. Could Harry's warm young heart contain
itself?
Why was I not there? A warning, a restraining word——. But would
Harry have heard it? Could I have spoken it? Would he not have felt,
must not I have felt with him, that this was one of those moments
when to see wrong done without protesting is to share in it? And
then rose before me the possible scenes:—the beautiful, glowing
face, the noble, passionate words, the tumult, the clamor, the scoff,
the threat, the—— Oh, no! surely the angels would have had charge
concerning him!
When we reached the summit of the last hill, my horse stopped of
himself, as if to let me receive well into my mind the first lovely
aspect of the town below us, and thus connect a charm with its
name which nearer knowledge should not be able to disturb.
I yielded to the influence of the scene the more easily that it was in
such contrast with my perturbed feelings. We may court and cherish
a fanciful or a superficial grief; but the bitterly tormented mind asks
ease as the tortured body does, and takes eagerly the soothing
draught from any hand. The landscape, still freshened by the night,
and already brilliant with the day, spoke peace and hope. I accepted
the promise. Descending the hill, I thought and reasoned cheerfully.
I smiled that I should have fancied nothing could happen in
Omocqua, when Harry was there, without his having a part in it.
This took place last evening; he had not heard of it yet, perhaps. Or
he had heard of it; but not until it was over, and there was nothing
to be done. He was commonly silent under strong emotion. He
would have heard this story as he had heard others of the sort, with
resolved composure, finding in it new food for his inward purpose.
On the outskirts of the town I came to a little tavern, the one
probably at which my acquaintance of the road had lodged. I had
almost stopped to ask the news, but thought better of it, and was
going on, when a man sitting on a bench under a tree started up
and ran after me, shouting. I stopped, and he came up out of
breath.
"You thought we were shut, seeing us so still; but we're all on
hand."
I explained, that I was going to the Jackson House, where a friend
was to meet me.
"The Jackson House! That's head-quarters for news, just now. All
right. You looked as if you wanted to stop."
"I thought of stopping for a moment. I heard on the road that there
had been some sort of disturbance in your town yesterday. Is all
quiet now?"
"For aught I know."
"I heard there was a boy shot here yesterday."
"A boy?"
"A runaway."
"One of our waiters brought down such a story last night. They are
sharp after news of their own. I told him 'twas wholesome, if it
turned out so. But this morning it comes that it was the man who
was running him off that was shot. You'll hear all about it at the
Jackson. If you come back this way, stop and give me a word. I can't
leave."
There were a number of men on the piazza of the Jackson House.
Most of them had the air of habitual loungers; a few were evidently
travellers newly arrived. Not a figure that even from a distance I
could take for Harry Dudley. Some trunks and valises were waiting to
be carried in, but I saw nothing familiar. I recognized the landlord in
a man who was leaning against a pillar, smoking. He did not come
forward, or even raise his eyes, when I rode up. I bade him good-
morning, addressing him by name. He came forward a little,—bowed
in answer to my salutation, but did not speak.
"Is Mr. Dudley here?"
Brompton did not reply. He threw out two or three puffs of smoke,
then took the cigar from his lips and flung it from him. He looked
serious, and, I thought, displeased. My misgivings returned. Had
Harry incurred ill-will by some generous imprudence? Had he left the
house, perhaps? Was the landlord afraid of being involved in his
guest's discredit?
He spoke at last, with effort.
"Is your name——?"
"Colvil."
He came down the steps and stood close to me, laying a hand on
my horse's neck and stroking down his mane.
"Mr. Colvil, I don't know that anybody is to blame; but an accident
has happened here. I'm sorry to be the one to tell you of it."
I dismounted. Brompton made several attempts at beginning, but
stopped again.
"You had some trouble in your town yesterday," I said; "can that in
any way concern Mr. Dudley?"
"Are you a near friend of his?"
"Yes."
"A relation?"
"No."
He went on with more assurance.
"Mr. Dudley was here about a month ago. He had a sick boy with
him, whom he left here, in a manner under my care. He was to have
taken him away to-day. He arrived yesterday afternoon and asked
me to send for the boy. I sent for him. Mr. Dudley was expecting you
yesterday afternoon, and walked over to the Jefferson to see if there
was any mistake.
"The boy was his. It was all regular. He had him of Ruffin, who never
does anything unhandsome. I knew all about it. Ruffin was here with
a lot of all sorts he had been picking up round the country. He told
me to keep the boy pretty close while I had him in charge; and I
boarded him outside the town, with an old granny, who didn't know
but he was really in hiding. But it was all right. He was a pet servant,
spoiled till he grew saucy, and his master swapped him off,—but
quietly, the family set so much by the boy. They were to think he'd
been enticed away. But it must happen, that, exactly yesterday
afternoon, one of the sons came riding up to this very house. He left
his horse to the servant he brought with him; then comes up to the
door and asks if Mr. Dudley is here; hears that he has walked out,
and so walks out too. The first thing he meets, just out here on the
square, is this boy, whom he had been fond of, and only over-kind
to. The boy checks up, and then, like a fool, turns and runs. The
young man calls to him to stop,—and then, to stop or he'd shoot.
The boy only runs faster. Dudley was crossing the square, on his way
back from the Jefferson, and came up at the moment. He told Orphy
to stand still, and, stepping right between him and the levelled
pistol, called to the other to hold on. But the man was so mad with
rage at seeing his servant flout him and mind another, that he could
not stop his hand. I was standing where you are now. I saw Dudley
come up, with his even step, just as usual. I heard his voice, clear
and cool. I did not look for mischief until I heard the crack of the
pistol,—and there he was on the ground! I ran down to him. I was
going to have him taken into the house, but he wanted to lie in the
open air. We carried him round to the green behind the barn. There
was an army-surgeon here, on his way West. He did what he could,
but said it was only a question of hours. Dudley knew it. He wanted
to keep on till morning, thinking you might come. He lasted till after
daybreak. Will you go to him?"
I followed Brompton into the house, along the entry, across the
yard, through the great barn. A road led from a gate on a side-street
to a shed. Before us, on the other side of the road, was a green field
with one great tree. The grass under the tree was flattened.
"Yes, it was there," said Brompton. "He asked to be laid under that
tree. The sun was just setting over there. When evening came, we
wanted to take him to the house; but no. We let him have his will. It
was natural he should want to see the sky while he could."
Brompton led the way to the shed.
What struggles must have rent that strong young breast before the
life was dislodged from it! How must the spirit which had known this
earth only through innocent joys and sweet affections and lovely
hopes,—how must it have clung to its dear mortal dwelling-place!
how mourned its dividing ties! how claimed its work, unfinished,
unbegun! This grief, this yearning, this reluctance would have left
their story on the cold immovable face. With these, bodily torture
would have done its part to alter and impair! I followed my guide,
foreboding that the dumb anguish in my heart was to be displaced
by a fiercer pain.
There was no pain in his presence. In death, as in life, he kept his
own gift of blessing. The holy light still lay on the brow; about the
lips hovered a smile, last ethereal trace of the ascended spirit. My
soul lifted itself to his. I understood the peace that passeth
understanding.
An angry voice brought me back to the world and its discords.
"Do you think you were worth it?"
I looked where Brompton was looking, and saw, seated near, on an
overturned barrel, a figure which could be no other than that of
Orphy. He sat impassive. Brompton's cruel words had not reached
him. His misery was its own shield. His utter wretchedness precluded
more. But he felt my look fixed upon him. He raised his eyes to me
for a moment, then closed them again to shut himself in with his
woe. And now his face quivered all over; his lips parted and closed
rapidly,—not as forming articulate accents, but in the helpless
forlornness that has no language in which to utter plaint or appeal.
And yet on these trembling cheeks, about this inane mouth, still
lingered some of the soft, playful lines I remembered on the pretty,
varying face of little Airy Harvey!
On the way from the house I was conscious that a step followed us,
stopping when we stopped, and going on again when we did; but I
had not given thought to it until now, when I perceived a timid
movement behind me, and felt a light touch laid on my arm. I
turned, and met a pair of mournful, pleading eyes.
"Jasper!"
The old man stretched one trembling hand toward the dead, while
the other clasped my wrist.—"It was not meant! It was not meant!"
"It was not," said Brompton.
"Do not bear anger! He did not."
"He did not," echoed Brompton.
Jasper, searching my face, saw there what changed his look of
entreaty into one of compassion. He stroked my sleeve soothingly
with his poor shrunken fingers.—"And yet there never was anything
but love between you! Oh, think there is a sorer heart than yours
this day!"
"Where is he?" I asked, fearing lest that most unhappy one might be
near.
"Gone."—It was Brompton who answered.—"Gone, I believe. He was
here until all was over. He locked himself into a room up-stairs.
Dudley sent for him many times the night through, in the intervals of
his pain. I took the messages to him. But he could neither bear to
see the one he had killed, nor yet to go away, and have no chance
of seeing him again. At daybreak Dudley got up, saying he had
strength enough, and went as far as the barn on his way to the
house. There the surgeon met him and led him back, pledging his
word that the man should be brought, if it was by force. And it was
almost by force, but he was brought. Dudley raised himself a little,
when he came up, took his hand and clasped it close. 'Good-bye,
Fred!'—in a pleasant voice, as if he were ready for a journey and
must cheer up the friend he was to leave behind. And then he sank
back, still holding the other's hand, and looking up at him with his
kind eyes, not forgiving, but loving,—till the eyelids drooped and
closed softly, and he passed into a quiet sleep. When we left him, he
was breathing gently. We thought it was rest."
Jasper went humbly away, secure of his suit. Brompton, too,
withdrew silently.
In those first moments I had left below my loss and my grief to
follow the ascended; but now my human heart asked after the
human friend.
On the rich, disordered hair were signs of the mortal agony: the soft,
bright curls were loosened and dimmed. The pure forehead could
not be fairer than it was, yet the even, delicately finished eyebrows
seemed more strongly marked. The brown eyelashes showed long
and dark over the white cheek. The same noble serenity; the same
gentle strength; only the resolute lines about the mouth were
softened;—nothing now to resist or to dare!
Dr. Borrow would be here soon. I sat down on a block and waited.
Dr. Borrow! I had thought his love for Harry tinctured with
worldliness; but how honest and hearty it appeared to me now! I
had loved in Harry Dudley what he was to be, what he was to do. Dr.
Borrow had loved him for himself only, simply and sincerely. I
remembered the Doctor's misgivings, his cautions to me. How
negligently heard! Then it was only that he did not yet comprehend
the high calling of the boy whom we equally loved. Now I almost felt
as if I had a complicity in his fate,—as if the Doctor could demand
account of me.
That Harry Dudley would give himself to a great cause had been my
hope and faith; that he would spend himself on a chimera had been
Doctor Borrow's dread. But which of us had looked forward to this
utter waste? How reconcile it with Divine Omnipotence? with
Supreme Justice? Was there not here frustration of a master-work?
Was there not here a promise unfulfilled?
Careless footsteps and voices gave notice of the approach of men
brought by curiosity. Seeing me, and judging me not one of
themselves, they stop outside, confer a moment in lower tones,
come in singly, look, and go out again.
Then new voices. A tall, stout man stalked heavily in. "And the boy
was his own, after all," burst from him as he rejoined the others.
"The boy was not his own. He didn't buy him fairly to keep and work
him. It was a sham sale. He meant to free him from the first, and
the boy knew it. He was free by intention and in fact. He had all the
mischief in him of a free negro."
"The man was a New-Englander, and saw it differently," answered
the first voice.
"A man is not a fool because he is a New-Englander," replied the
second. "I am from New England myself."
"I don't see much of the same about you. Are there more there like
him or like you?"
"I tell you he has died as the fool dieth," the other answered sharply,
coming carelessly in as he spoke. He was a mean-looking man,
trimly dressed, in whom I could not but recognize the Yankee
schoolmaster.
As he stooped down over the man he had contemned, some
dormant inheritance of manhood revealed itself in his breast, some
lingering trace of richer blood stirred in his dull veins. He turned
away, cast towards me a humble, deprecating look, and, still
bending forward, went out on tiptoe.
Then, accompanied by a sweeping and a rustling, came a light step,
but a decided, and, I felt, an indifferent one. A woman came in. She
took account with imperious eyes of every object,—of me, of Orphy,
of the coarse bench spread with hay, which served as bier,—and
then walked confidently and coldly forward to the spectacle of death.
When she had sight of the beautiful young face, she uttered a cry,
then burst into passionate sobs, which she silenced as suddenly,
turned, shook her fist at Orphy, and was gone.
"Dr. Borrow is come."
Come! To what a different appointment!
"He asked for you," persisted Brompton, seeing that I did not rise.
"He is in the same room he had when they were here together. He
mistrusted something, or he had heard something; he said no word
until he was there. Then he asked me what he had got to be told,
and I told him."
I made a sign that I would go. Brompton left me with a look which
showed that he knew what a part I had before me.
Dr. Borrow was not a patient man. He was ruffled by a slight
contrariety. This unimagined grief, how was it to be borne? With
what words would he receive me? Would he even spare Harry
Dudley himself, in the reproaches which his love would only make
more bitter?
We three were to have met to-day. Was he the one to be wanting?
he who was never wanting? He who had been the life, the joy, of
those dearly remembered hours, was he to be the sorrow, the
burden of these? I went to him again; again earth and its anxieties
vanished from me. No, he would not be wanting to us.
When I touched the handle of the door, it was turned from the
inside. Dr. Borrow seized my hand, clasping it, not in greeting, but
like one who clings for succor. He searched my face with ardently
questioning look, as if I might have brought him mercy or reprieve.
He saw that I had not. A spasm passed over his face. His mouth
opened to speak, with voiceless effort. He motioned me to lead
where he was to go. We went down-stairs, and he followed me, as I
had followed Brompton, along the entry, across the yard, through
the barn. He glanced towards the tree and then took his way to the
shed. I did not enter with him.
When he came back to me, he was very pale, but his expression was
soft and tender as I had never known it. We went in again together,
and stood there side by side.
Brompton spoke from without. "There is one thing I have not told
you, Dr. Borrow."
The Doctor turned to him patiently.
"There was an inquest held early this morning."
Dr. Borrow lifted his hand to ward off more.
"Let me take my child and go!"
The Doctor looked towards Orphy. Again I had almost wronged him
in my thought. "Come, my lad," he said, kindly; "you and I must
take care of him home."
Orphy left his place of watch. He came and stood close beside the
Doctor, devoting his allegiance; tears gathered in the eyes that the
soul looked through once more; the mouth retook its own pathetic
smile.
I knew that Harry Dudley must lie in Massachusetts ground, but I
could not look my last so soon. Dr. Borrow saw my intention and
prevented it. He took my hand affectionately, yet as holding me from
him.
"Do not come. I am better off without you. I must battle this out
alone."
Then, a moment after, as feeling he had amends to make,—
"You have known him a few weeks. Think what I have lost,—the
child, the boy, the man! All my hopes were in him,—I did not myself
know how wholly!"
And beyond this anguish lay other, that he would have put off till its
time, but it pressed forward.
"Colvil, you are going home. You go to be consoled. What am I
going to?"
On the side-street, the swift tread of horses and the roll of rapid
wheels. A wagon stopped before the gate. What a joy Charles
Shaler's coming was to have been to us!
He was prepared. He came forward erect and stern. He saluted us
gravely in passing, went in and stood beside the bier. He remained
gazing intently for a little time,—then, laying his hand lightly on the
sacred forehead, raised his look to heaven. He came out composed
as he had entered.
Shaler spoke apart with Brompton, and returned to us.
"You would leave this place as soon as possible?" he said to Dr.
Borrow.
"Yes."
I had meant to combat the Doctor's desire that I should leave him,—
not for my own sake, but because I thought he would need me; but
I submitted now. Shaler would assume every care, and I saw that
Dr. Borrow yielded himself up implicitly.
The moment came. We lifted him reverently, Orphy propping with
his weak hands the arm that had once lent him its strength. We
carried him out into the sunshine he had loved, bright then as if it
still shone for him. The wind ruffled the lifeless hair whose sparkling
curls I had seen it caress so often.
It is over. Over with the last meeting, the last parting. Over with that
career in which I was to have lived, oh, how much more than in my
Welcome to our website – the ideal destination for book lovers and
knowledge seekers. With a mission to inspire endlessly, we offer a
vast collection of books, ranging from classic literary works to
specialized publications, self-development books, and children's
literature. Each book is a new journey of discovery, expanding
knowledge and enriching the soul of the reade
Our website is not just a platform for buying books, but a bridge
connecting readers to the timeless values of culture and wisdom. With
an elegant, user-friendly interface and an intelligent search system,
we are committed to providing a quick and convenient shopping
experience. Additionally, our special promotions and home delivery
services ensure that you save time and fully enjoy the joy of reading.
Let us accompany you on the journey of exploring knowledge and
personal growth!
textbookfull.com

High Performance Python Practical Performant Programming for Humans 2nd Edition Micha Gorelick Ian Ozsvald

  • 1.
    Explore the fullebook collection and download it now at textbookfull.com High Performance Python Practical Performant Programming for Humans 2nd Edition Micha Gorelick Ian Ozsvald https://textbookfull.com/product/high-performance-python- practical-performant-programming-for-humans-2nd-edition- micha-gorelick-ian-ozsvald/ OR CLICK HERE DOWLOAD EBOOK Browse and Get More Ebook Downloads Instantly at https://textbookfull.com Click here to visit textbookfull.com and download textbook now
  • 2.
    Your digital treasures(PDF, ePub, MOBI) await Download instantly and pick your perfect format... Read anywhere, anytime, on any device! Parallel programming for modern high performance computing systems Czarnul https://textbookfull.com/product/parallel-programming-for-modern-high- performance-computing-systems-czarnul/ textbookfull.com Automate the Boring Stuff with Python, 2nd Edition: Practical Programming for Total Beginners Al Sweigart https://textbookfull.com/product/automate-the-boring-stuff-with- python-2nd-edition-practical-programming-for-total-beginners-al- sweigart/ textbookfull.com Black Hat Python: Python Programming for Hackers and Pentesters 2nd Edition Justin Seitz https://textbookfull.com/product/black-hat-python-python-programming- for-hackers-and-pentesters-2nd-edition-justin-seitz/ textbookfull.com Julia High Performance 2nd Edition Avik Sengupta https://textbookfull.com/product/julia-high-performance-2nd-edition- avik-sengupta/ textbookfull.com
  • 3.
    Beginning Programming withPython For Dummies 2nd Edition John Paul Mueller https://textbookfull.com/product/beginning-programming-with-python- for-dummies-2nd-edition-john-paul-mueller/ textbookfull.com Practical Foundations For Programming Languages 2nd Edition Robert Harper https://textbookfull.com/product/practical-foundations-for- programming-languages-2nd-edition-robert-harper/ textbookfull.com Routledge Handbook of Strength and Conditioning Sport Specific Programming for High Performance Anthony Turner https://textbookfull.com/product/routledge-handbook-of-strength-and- conditioning-sport-specific-programming-for-high-performance-anthony- turner/ textbookfull.com A Practical Approach to High-Performance Computing Sergei Kurgalin https://textbookfull.com/product/a-practical-approach-to-high- performance-computing-sergei-kurgalin/ textbookfull.com Python Network Programming Cookbook Practical solutions to overcome real world networking challenges 2nd Edition Pradeeban Kathiravelu https://textbookfull.com/product/python-network-programming-cookbook- practical-solutions-to-overcome-real-world-networking-challenges-2nd- edition-pradeeban-kathiravelu/ textbookfull.com
  • 5.
    S e c o n d E d i t i o n Micha Gorelick &Ian Ozsvald High Performance Python Practical Performant Programming for Humans
  • 7.
    Micha Gorelick andIan Ozsvald High Performance Python Practical Performant Programming for Humans SECOND EDITION Boston Farnham Sebastopol Tokyo Beijing Boston Farnham Sebastopol Tokyo Beijing
  • 8.
    978-1-492-05502-0 [LSI] High Performance Python byMicha Gorelick and Ian Ozsvald Copyright © 2020 Micha Gorelick and Ian Ozsvald. All rights reserved. Printed in the United States of America. Published by O’Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472. O’Reilly books may be purchased for educational, business, or sales promotional use. Online editions are also available for most titles (http://oreilly.com). For more information, contact our corporate/institu‐ tional sales department: 800-998-9938 or corporate@oreilly.com. Acquisitions Editor: Tyler Ortman Indexer: Potomac Indexing, LLC Development Editor: Sarah Grey Interior Designer: David Futato Production Editor: Christopher Faucher Cover Designer: Karen Montgomery Copyeditor: Arthur Johnson Illustrator: Rebecca Demarest Proofreader: Sharon Wilkey September 2014: First Edition May 2020: Second Edition Revision History for the Second Edition 2020-04-30: First release See http://oreilly.com/catalog/errata.csp?isbn=9781492055020 for release details. The O’Reilly logo is a registered trademark of O’Reilly Media, Inc. High Performance Python, the cover image, and related trade dress are trademarks of O’Reilly Media, Inc. The views expressed in this work are those of the authors, and do not represent the publisher’s views. While the publisher and the authors have used good faith efforts to ensure that the information and instructions contained in this work are accurate, the publisher and the authors disclaim all responsibility for errors or omissions, including without limitation responsibility for damages resulting from the use of or reliance on this work. Use of the information and instructions contained in this work is at your own risk. If any code samples or other technology this work contains or describes is subject to open source licenses or the intellectual property rights of others, it is your responsibility to ensure that your use thereof complies with such licenses and/or rights. High Performance Python is available under the Creative Commons Attribution-NonCommercial- NoDerivs 3.0 International License.
  • 9.
    Table of Contents Foreword.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi Preface. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii 1. Understanding Performant Python. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 The Fundamental Computer System 2 Computing Units 2 Memory Units 5 Communications Layers 8 Putting the Fundamental Elements Together 10 Idealized Computing Versus the Python Virtual Machine 10 So Why Use Python? 14 How to Be a Highly Performant Programmer 16 Good Working Practices 17 Some Thoughts on Good Notebook Practice 19 Getting the Joy Back into Your Work 20 2. Profiling to Find Bottlenecks. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 Profiling Efficiently 22 Introducing the Julia Set 23 Calculating the Full Julia Set 26 Simple Approaches to Timing—print and a Decorator 30 Simple Timing Using the Unix time Command 33 Using the cProfile Module 35 Visualizing cProfile Output with SnakeViz 39 Using line_profiler for Line-by-Line Measurements 40 Using memory_profiler to Diagnose Memory Usage 46 Introspecting an Existing Process with PySpy 54 iii
  • 10.
    Bytecode: Under theHood 55 Using the dis Module to Examine CPython Bytecode 55 Different Approaches, Different Complexity 57 Unit Testing During Optimization to Maintain Correctness 59 No-op @profile Decorator 60 Strategies to Profile Your Code Successfully 62 Wrap-Up 64 3. Lists and Tuples. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 A More Efficient Search 68 Lists Versus Tuples 71 Lists as Dynamic Arrays 72 Tuples as Static Arrays 76 Wrap-Up 77 4. Dictionaries and Sets. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 How Do Dictionaries and Sets Work? 83 Inserting and Retrieving 83 Deletion 87 Resizing 87 Hash Functions and Entropy 88 Dictionaries and Namespaces 92 Wrap-Up 95 5. Iterators and Generators. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 Iterators for Infinite Series 101 Lazy Generator Evaluation 103 Wrap-Up 107 6. Matrix and Vector Computation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 Introduction to the Problem 110 Aren’t Python Lists Good Enough? 115 Problems with Allocating Too Much 117 Memory Fragmentation 120 Understanding perf 122 Making Decisions with perf’s Output 125 Enter numpy 126 Applying numpy to the Diffusion Problem 129 Memory Allocations and In-Place Operations 133 Selective Optimizations: Finding What Needs to Be Fixed 137 numexpr: Making In-Place Operations Faster and Easier 140 A Cautionary Tale: Verify “Optimizations” (scipy) 142 iv | Table of Contents
  • 11.
    Lessons from MatrixOptimizations 143 Pandas 146 Pandas’s Internal Model 146 Applying a Function to Many Rows of Data 148 Building DataFrames and Series from Partial Results Rather than Concatenating 156 There’s More Than One (and Possibly a Faster) Way to Do a Job 157 Advice for Effective Pandas Development 159 Wrap-Up 160 7. Compiling to C. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 What Sort of Speed Gains Are Possible? 162 JIT Versus AOT Compilers 164 Why Does Type Information Help the Code Run Faster? 164 Using a C Compiler 165 Reviewing the Julia Set Example 166 Cython 167 Compiling a Pure Python Version Using Cython 167 pyximport 169 Cython Annotations to Analyze a Block of Code 170 Adding Some Type Annotations 172 Cython and numpy 176 Parallelizing the Solution with OpenMP on One Machine 178 Numba 180 Numba to Compile NumPy for Pandas 182 PyPy 183 Garbage Collection Differences 184 Running PyPy and Installing Modules 185 A Summary of Speed Improvements 186 When to Use Each Technology 187 Other Upcoming Projects 188 Graphics Processing Units (GPUs) 189 Dynamic Graphs: PyTorch 190 Basic GPU Profiling 193 Performance Considerations of GPUs 194 When to Use GPUs 196 Foreign Function Interfaces 197 ctypes 199 cffi 201 f2py 204 CPython Module 207 Wrap-Up 211 Table of Contents | v
  • 12.
    8. Asynchronous I/O.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 Introduction to Asynchronous Programming 215 How Does async/await Work? 218 Serial Crawler 219 Gevent 221 tornado 226 aiohttp 229 Shared CPU–I/O Workload 233 Serial 233 Batched Results 235 Full Async 238 Wrap-Up 243 9. The multiprocessing Module. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245 An Overview of the multiprocessing Module 248 Estimating Pi Using the Monte Carlo Method 250 Estimating Pi Using Processes and Threads 251 Using Python Objects 252 Replacing multiprocessing with Joblib 260 Random Numbers in Parallel Systems 263 Using numpy 264 Finding Prime Numbers 267 Queues of Work 273 Verifying Primes Using Interprocess Communication 278 Serial Solution 283 Naive Pool Solution 284 A Less Naive Pool Solution 285 Using Manager.Value as a Flag 286 Using Redis as a Flag 288 Using RawValue as a Flag 290 Using mmap as a Flag 291 Using mmap as a Flag Redux 293 Sharing numpy Data with multiprocessing 295 Synchronizing File and Variable Access 301 File Locking 302 Locking a Value 305 Wrap-Up 308 10. Clusters and Job Queues. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311 Benefits of Clustering 312 Drawbacks of Clustering 313 $462 Million Wall Street Loss Through Poor Cluster Upgrade Strategy 315 vi | Table of Contents
  • 13.
    Skype’s 24-Hour GlobalOutage 315 Common Cluster Designs 316 How to Start a Clustered Solution 317 Ways to Avoid Pain When Using Clusters 318 Two Clustering Solutions 319 Using IPython Parallel to Support Research 319 Parallel Pandas with Dask 322 NSQ for Robust Production Clustering 326 Queues 327 Pub/sub 328 Distributed Prime Calculation 330 Other Clustering Tools to Look At 334 Docker 335 Docker’s Performance 335 Advantages of Docker 339 Wrap-Up 340 11. Using Less RAM. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341 Objects for Primitives Are Expensive 342 The array Module Stores Many Primitive Objects Cheaply 344 Using Less RAM in NumPy with NumExpr 346 Understanding the RAM Used in a Collection 350 Bytes Versus Unicode 352 Efficiently Storing Lots of Text in RAM 353 Trying These Approaches on 11 Million Tokens 354 Modeling More Text with Scikit-Learn’s FeatureHasher 362 Introducing DictVectorizer and FeatureHasher 362 Comparing DictVectorizer and FeatureHasher on a Real Problem 365 SciPy’s Sparse Matrices 366 Tips for Using Less RAM 370 Probabilistic Data Structures 371 Very Approximate Counting with a 1-Byte Morris Counter 372 K-Minimum Values 375 Bloom Filters 379 LogLog Counter 385 Real-World Example 389 12. Lessons from the Field. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393 Streamlining Feature Engineering Pipelines with Feature-engine 394 Feature Engineering for Machine Learning 394 The Hard Task of Deploying Feature Engineering Pipelines 395 Leveraging the Power of Open Source Python Libraries 395 Table of Contents | vii
  • 14.
    Feature-engine Smooths Buildingand Deployment of Feature Engineering Pipelines 396 Helping with the Adoption of a New Open Source Package 397 Developing, Maintaining, and Encouraging Contribution to Open Source Libraries 398 Highly Performant Data Science Teams 400 How Long Will It Take? 400 Discovery and Planning 401 Managing Expectations and Delivery 402 Numba 403 A Simple Example 404 Best Practices and Recommendations 405 Getting Help 409 Optimizing Versus Thinking 409 Adaptive Lab’s Social Media Analytics (2014) 412 Python at Adaptive Lab 413 SoMA’s Design 413 Our Development Methodology 414 Maintaining SoMA 414 Advice for Fellow Engineers 415 Making Deep Learning Fly with RadimRehurek.com (2014) 415 The Sweet Spot 416 Lessons in Optimizing 417 Conclusion 420 Large-Scale Productionized Machine Learning at Lyst.com (2014) 420 Cluster Design 420 Code Evolution in a Fast-Moving Start-Up 421 Building the Recommendation Engine 421 Reporting and Monitoring 422 Some Advice 422 Large-Scale Social Media Analysis at Smesh (2014) 422 Python’s Role at Smesh 423 The Platform 423 High Performance Real-Time String Matching 424 Reporting, Monitoring, Debugging, and Deployment 425 PyPy for Successful Web and Data Processing Systems (2014) 426 Prerequisites 427 The Database 428 The Web Application 428 OCR and Translation 429 Task Distribution and Workers 429 Conclusion 429 viii | Table of Contents
  • 15.
    Task Queues atLanyrd.com (2014) 430 Python’s Role at Lanyrd 430 Making the Task Queue Performant 431 Reporting, Monitoring, Debugging, and Deployment 431 Advice to a Fellow Developer 431 Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433 Table of Contents | ix
  • 17.
    Foreword When you thinkabout high performance computing, you might imagine giant clus‐ ters of machines modeling complex weather phenomena or trying to understand sig‐ nals in data collected about far-off stars. It’s easy to assume that only people building specialized systems should worry about the performance characteristics of their code. By picking up this book, you’ve taken a step toward learning the theory and practices you’ll need to write highly performant code. Every programmer can benefit from understanding how to build performant systems. There are an obvious set of applications that are just on the edge of possible, and you won’t be able to approach them without writing optimally performant code. If that’s your practice, you’re in the right place. But there is a much broader set of applica‐ tions that can benefit from performant code. We often think that new technical capabilities are what drives innovation, but I’m equally fond of capabilities that increase the accessibility of technology by orders of magnitude. When something becomes ten times cheaper in time or compute costs, suddenly the set of applications you can address is wider than you imagined. The first time this principle manifested in my own work was over a decade ago, when I was working at a social media company, and we ran an analysis over multiple tera‐ bytes of data to determine whether people clicked on more photos of cats or dogs on social media. It was dogs, of course. Cats just have better branding. This was an outstandingly frivolous use of compute time and infrastructure at the time! Gaining the ability to apply techniques that had previously been restricted to sufficiently high-value applications, such as fraud detection, to a seemingly trivial question opened up a new world of now-accessible possibilities. We were able to take what we learned from these experiments and build a whole new set of products in search and content discovery. Foreword | xi
  • 18.
    For an examplethat you might encounter today, consider a machine-learning system that recognizes unexpected animals or people in security video footage. A sufficiently performant system could allow you to embed that model into the camera itself, improving privacy or, even if running in the cloud, using significantly less compute and power—benefiting the environment and reducing your operating costs. This can free up resources for you to look at adjacent problems, potentially building a more valuable system. We all desire to create systems that are effective, easy to understand, and performant. Unfortunately, it often feels like we have to pick two (or one) out of the three! High Performance Python is a handbook for people who want to make things that are capa‐ ble of all three. This book stands apart from other texts on the subject in three ways. First, it’s written for us—humans who write code. You’ll find all of the context you need to understand why you might make certain choices. Second, Gorelick and Ozsvald do a wonderful job of curating and explaining the necessary theory to support that context. Finally, in this updated edition, you’ll learn the specific quirks of the most useful libraries for implementing these approaches today. This is one of a rare class of programming books that will change the way you think about the practice of programming. I’ve given this book to many people who could benefit from the additional tools it provides. The ideas that you’ll explore in its pages will make you a better programmer, no matter what language or environment you choose to work in. Enjoy the adventure. — Hilary Mason, Data Scientist in Residence at Accel xii | Foreword
  • 19.
    Preface Python is easyto learn. You’re probably here because now that your code runs cor‐ rectly, you need it to run faster. You like the fact that your code is easy to modify and you can iterate with ideas quickly. The trade-off between easy to develop and runs as quickly as I need is a well-understood and often-bemoaned phenomenon. There are solutions. Some people have serial processes that have to run faster. Others have problems that could take advantage of multicore architectures, clusters, or graphics processing units. Some need scalable systems that can process more or less as expediency and funds allow, without losing reliability. Others will realize that their coding techni‐ ques, often borrowed from other languages, perhaps aren’t as natural as examples they see from others. In this book we will cover all of these topics, giving practical guidance for under‐ standing bottlenecks and producing faster and more scalable solutions. We also include some war stories from those who went ahead of you, who took the knocks so you don’t have to. Python is well suited for rapid development, production deployments, and scalable systems. The ecosystem is full of people who are working to make it scale on your behalf, leaving you more time to focus on the more challenging tasks around you. Who This Book Is For You’ve used Python for long enough to have an idea about why certain things are slow and to have seen technologies like Cython, numpy, and PyPy being discussed as possible solutions. You might also have programmed with other languages and so know that there’s more than one way to solve a performance problem. While this book is primarily aimed at people with CPU-bound problems, we also look at data transfer and memory-bound solutions. Typically, these problems are faced by scientists, engineers, quants, and academics. Preface | xiii
  • 20.
    We also lookat problems that a web developer might face, including the movement of data and the use of just-in-time (JIT) compilers like PyPy and asynchronous I/O for easy-win performance gains. It might help if you have a background in C (or C++, or maybe Java), but it isn’t a prerequisite. Python’s most common interpreter (CPython—the standard you nor‐ mally get if you type python at the command line) is written in C, and so the hooks and libraries all expose the gory inner C machinery. There are lots of other techniques that we cover that don’t assume any knowledge of C. You might also have a lower-level knowledge of the CPU, memory architecture, and data buses, but again, that’s not strictly necessary. Who This Book Is Not For This book is meant for intermediate to advanced Python programmers. Motivated novice Python programmers may be able to follow along as well, but we recommend having a solid Python foundation. We don’t cover storage-system optimization. If you have a SQL or NoSQL bottle‐ neck, then this book probably won’t help you. What You’ll Learn Your authors have been working with large volumes of data, a requirement for I want the answers faster! and a need for scalable architectures, for many years in both industry and academia. We’ll try to impart our hard-won experience to save you from making the mistakes that we’ve made. At the start of each chapter, we’ll list questions that the following text should answer. (If it doesn’t, tell us and we’ll fix it in the next revision!) We cover the following topics: • Background on the machinery of a computer so you know what’s happening behind the scenes • Lists and tuples—the subtle semantic and speed differences in these fundamental data structures • Dictionaries and sets—memory allocation strategies and access algorithms in these important data structures • Iterators—how to write in a more Pythonic way and open the door to infinite data streams using iteration • Pure Python approaches—how to use Python and its modules effectively xiv | Preface
  • 21.
    • Matrices withnumpy—how to use the beloved numpy library like a beast • Compilation and just-in-time computing—processing faster by compiling down to machine code, making sure you’re guided by the results of profiling • Concurrency—ways to move data efficiently • multiprocessing—various ways to use the built-in multiprocessing library for parallel computing and to efficiently share numpy matrices, and some costs and benefits of interprocess communication (IPC) • Cluster computing—convert your multiprocessing code to run on a local or remote cluster for both research and production systems • Using less RAM—approaches to solving large problems without buying a humungous computer • Lessons from the field—lessons encoded in war stories from those who took the blows so you don’t have to Python 3 Python 3 is the standard version of Python as of 2020, with Python 2.7 deprecated after a 10-year migration process. If you’re still on Python 2.7, you’re doing it wrong —many libraries are no longer supported for your line of Python, and support will become more expensive over time. Please do the community a favor and migrate to Python 3, and make sure that all new projects use Python 3. In this book, we use 64-bit Python. Whilst 32-bit Python is supported, it is far less common for scientific work. We’d expect all the libraries to work as usual, but numeric precision, which depends on the number of bits available for counting, is likely to change. 64-bit is dominant in this field, along with *nix environments (often Linux or Mac). 64-bit lets you address larger amounts of RAM. *nix lets you build applications that can be deployed and configured in well-understood ways with well- understood behaviors. If you’re a Windows user, you’ll have to buckle up. Most of what we show will work just fine, but some things are OS-specific, and you’ll have to research a Windows sol‐ ution. The biggest difficulty a Windows user might face is the installation of modules: research in sites like Stack Overflow should give you the solutions you need. If you’re on Windows, having a virtual machine (e.g., using VirtualBox) with a running Linux installation might help you to experiment more freely. Windows users should definitely look at a packaged solution like those available through Anaconda, Canopy, Python(x,y), or Sage. These same distributions will make the lives of Linux and Mac users far simpler too. Preface | xv
  • 22.
    Changes from Python2.7 If you’ve upgraded from Python 2.7, you might not be aware of a few relevant changes: • / meant integer division in Python 2.7, whereas it performs float division in Python 3. • str and unicode were used to represent text data in Python 2.7; in Python 3, everything is a str, and these are always Unicode. For clarity, a bytes type is used if we’re using unencoded byte sequences. If you’re in the process of upgrading your code, two good guides are “Porting Python 2 Code to Python 3” and “Supporting Python 3: An in-depth guide”. With a distribu‐ tion like Anaconda or Canopy, you can run both Python 2 and Python 3 simultane‐ ously—this will simplify your porting. License This book is licensed under Creative Commons Attribution-NonCommercial- NoDerivs 3.0. You’re welcome to use this book for noncommercial purposes, including for noncommercial teaching. The license allows only for complete reproductions; for partial reproductions, please contact O’Reilly (see “How to Contact Us” on page xviii). Please attribute the book as noted in the following section. We negotiated that the book should have a Creative Commons license so the con‐ tents could spread further around the world. We’d be quite happy to receive a beer if this decision has helped you. We suspect that the O’Reilly staff would feel similarly about the beer. How to Make an Attribution The Creative Commons license requires that you attribute your use of a part of this book. Attribution just means that you should write something that someone else can follow to find this book. The following would be sensible: “High Performance Python, 2nd ed., by Micha Gorelick and Ian Ozsvald (O’Reilly). Copyright 2020 Micha Gore‐ lick and Ian Ozsvald, 978-1-492-05502-0.” xvi | Preface
  • 23.
    Errata and Feedback Weencourage you to review this book on public sites like Amazon—please help oth‐ ers understand if they would benefit from this book! You can also email us at feedback@highperformancepython.com. We’re particularly keen to hear about errors in the book, successful use cases where the book has helped you, and high performance techniques that we should cover in the next edition. You can access the web page for this book at https://oreil.ly/high- performance-python-2e. Complaints are welcomed through the instant-complaint-transmission-service > /dev/null. Conventions Used in This Book The following typographical conventions are used in this book: Italic Indicates new terms, URLs, email addresses, filenames, and file extensions. Constant width Used for program listings, as well as within paragraphs to refer to program ele‐ ments such as variable or function names, databases, datatypes, environment variables, statements, and keywords. Constant width bold Shows commands or other text that should be typed literally by the user. Constant width italic Shows text that should be replaced with user-supplied values or by values deter‐ mined by context. This element signifies a tip, suggestion, or critical thinking ques‐ tion. This element signifies a general note. Preface | xvii
  • 24.
    This element indicatesa warning or caution. Using Code Examples Supplemental material (code examples, exercises, etc.) is available for download at https://github.com/mynameisfiber/high_performance_python_2e. If you have a technical question or a problem using the code examples, please send email to bookquestions@oreilly.com. This book is here to help you get your job done. In general, if example code is offered with this book, you may use it in your programs and documentation. You do not need to contact us for permission unless you’re reproducing a significant portion of the code. For example, writing a program that uses several chunks of code from this book does not require permission. Selling or distributing examples from O’Reilly books does require permission. Answering a question by citing this book and quoting example code does not require permission. Incorporating a significant amount of example code from this book into your product’s documentation does require permission. If you feel your use of code examples falls outside fair use or the permission given above, feel free to contact us at permissions@oreilly.com. O’Reilly Online Learning For more than 40 years, O’Reilly Media has provided technol‐ ogy and business training, knowledge, and insight to help companies succeed. Our unique network of experts and innovators share their knowledge and expertise through books, articles, and our online learning platform. O’Reilly’s online learning platform gives you on-demand access to live training courses, in-depth learning paths, interactive coding environments, and a vast collection of text and video from O’Reilly and 200+ other publishers. For more information, visit http://oreilly.com. How to Contact Us Please address comments and questions concerning this book to the publisher: xviii | Preface
  • 25.
    O’Reilly Media, Inc. 1005Gravenstein Highway North Sebastopol, CA 95472 800-998-9938 (in the United States or Canada) 707-829-0515 (international or local) 707-829-0104 (fax) Email bookquestions@oreilly.com to comment or ask technical questions about this book. For news and more information about our books and courses, see our website at http://oreilly.com. Find us on Facebook: http://facebook.com/oreilly Follow us on Twitter: http://twitter.com/oreillymedia Watch us on YouTube: http://youtube.com/oreillymedia Acknowledgments Hilary Mason wrote our foreword—thanks for composing such a wonderful opening narrative for our book. Giles Weaver and Dimitri Denisjonok provided invaluable technical feedback on this edition; great work, chaps. Thanks to Patrick Cooper, Kyran Dale, Dan Foreman-Mackey, Calvin Giles, Brian Granger, Jamie Matthews, John Montgomery, Christian Schou Oxvig, Matt “snakes” Reiferson, Balthazar Rouberol, Michael Skirpan, Luke Underwood, Jake Vanderplas, and William Winter for invaluable feedback and contributions. Ian thanks his wife, Emily, for letting him disappear for another eight months to write this second edition (thankfully, she’s terribly understanding). Ian apologizes to his dog for sitting and writing rather than walking in the woods quite as much as she’d have liked. Micha thanks Marion and the rest of his friends and family for being so patient while he learned to write. O’Reilly editors are rather lovely to work with; do strongly consider talking to them if you want to write your own book. Our contributors to the “Lessons from the Field” chapter very kindly shared their time and hard-won lessons. We give thanks to Soledad Galli, Linda Uruchurtu, Vanentin Haenel, and Vincent D. Warmerdam for this edition and to Ben Jackson, Radim Řehůřek, Sebastjan Trepca, Alex Kelly, Marko Tasic, and Andrew Godwin for their time and effort during the previous edition. Preface | xix
  • 27.
    CHAPTER 1 Understanding PerformantPython Questions You’ll Be Able to Answer After This Chapter • What are the elements of a computer’s architecture? • What are some common alternate computer architectures? • How does Python abstract the underlying computer architecture? • What are some of the hurdles to making performant Python code? • What strategies can help you become a highly performant programmer? Programming computers can be thought of as moving bits of data and transforming them in special ways to achieve a particular result. However, these actions have a time cost. Consequently, high performance programming can be thought of as the act of minimizing these operations either by reducing the overhead (i.e., writing more effi‐ cient code) or by changing the way that we do these operations to make each one more meaningful (i.e., finding a more suitable algorithm). Let’s focus on reducing the overhead in code in order to gain more insight into the actual hardware on which we are moving these bits. This may seem like a futile exer‐ cise, since Python works quite hard to abstract away direct interactions with the hardware. However, by understanding both the best way that bits can be moved in the real hardware and the ways that Python’s abstractions force your bits to move, you can make progress toward writing high performance programs in Python. 1
  • 28.
    The Fundamental ComputerSystem The underlying components that make up a computer can be simplified into three basic parts: the computing units, the memory units, and the connections between them. In addition, each of these units has different properties that we can use to understand them. The computational unit has the property of how many computa‐ tions it can do per second, the memory unit has the properties of how much data it can hold and how fast we can read from and write to it, and finally, the connections have the property of how fast they can move data from one place to another. Using these building blocks, we can talk about a standard workstation at multiple lev‐ els of sophistication. For example, the standard workstation can be thought of as hav‐ ing a central processing unit (CPU) as the computational unit, connected to both the random access memory (RAM) and the hard drive as two separate memory units (each having different capacities and read/write speeds), and finally a bus that pro‐ vides the connections between all of these parts. However, we can also go into more detail and see that the CPU itself has several memory units in it: the L1, L2, and sometimes even the L3 and L4 cache, which have small capacities but very fast speeds (from several kilobytes to a dozen megabytes). Furthermore, new computer architec‐ tures generally come with new configurations (for example, Intel’s SkyLake CPUs replaced the frontside bus with the Intel Ultra Path Interconnect and restructured many connections). Finally, in both of these approximations of a workstation we have neglected the network connection, which is effectively a very slow connection to potentially many other computing and memory units! To help untangle these various intricacies, let’s go over a brief description of these fundamental blocks. Computing Units The computing unit of a computer is the centerpiece of its usefulness—it provides the ability to transform any bits it receives into other bits or to change the state of the current process. CPUs are the most commonly used computing unit; however, graphics processing units (GPUs) are gaining popularity as auxiliary computing units. They were originally used to speed up computer graphics but are becoming more applicable for numerical applications and are useful thanks to their intrinsically parallel nature, which allows many calculations to happen simultaneously. Regardless of its type, a computing unit takes in a series of bits (for example, bits representing numbers) and outputs another set of bits (for example, bits representing the sum of those numbers). In addition to the basic arithmetic operations on integers and real numbers and bitwise operations on binary numbers, some computing units also pro‐ vide very specialized operations, such as the “fused multiply add” operation, which takes in three numbers, A, B, and C, and returns the value A * B + C. 2 | Chapter 1: Understanding Performant Python
  • 29.
    1 Not tobe confused with interprocess communication, which shares the same acronym—we’ll look at that topic in Chapter 9. The main properties of interest in a computing unit are the number of operations it can do in one cycle and the number of cycles it can do in one second. The first value is measured by its instructions per cycle (IPC),1 while the latter value is measured by its clock speed. These two measures are always competing with each other when new computing units are being made. For example, the Intel Core series has a very high IPC but a lower clock speed, while the Pentium 4 chip has the reverse. GPUs, on the other hand, have a very high IPC and clock speed, but they suffer from other prob‐ lems like the slow communications that we discuss in “Communications Layers” on page 8. Furthermore, although increasing clock speed almost immediately speeds up all pro‐ grams running on that computational unit (because they are able to do more calcula‐ tions per second), having a higher IPC can also drastically affect computing by changing the level of vectorization that is possible. Vectorization occurs when a CPU is provided with multiple pieces of data at a time and is able to operate on all of them at once. This sort of CPU instruction is known as single instruction, multiple data (SIMD). In general, computing units have advanced quite slowly over the past decade (see Figure 1-1). Clock speeds and IPC have both been stagnant because of the physical limitations of making transistors smaller and smaller. As a result, chip manufacturers have been relying on other methods to gain more speed, including simultaneous mul‐ tithreading (where multiple threads can run at once), more clever out-of-order exe‐ cution, and multicore architectures. Hyperthreading presents a virtual second CPU to the host operating system (OS), and clever hardware logic tries to interleave two threads of instructions into the exe‐ cution units on a single CPU. When successful, gains of up to 30% over a single thread can be achieved. Typically, this works well when the units of work across both threads use different types of execution units—for example, one performs floating- point operations and the other performs integer operations. Out-of-order execution enables a compiler to spot that some parts of a linear pro‐ gram sequence do not depend on the results of a previous piece of work, and there‐ fore that both pieces of work could occur in any order or at the same time. As long as sequential results are presented at the right time, the program continues to execute correctly, even though pieces of work are computed out of their programmed order. This enables some instructions to execute when others might be blocked (e.g., wait‐ ing for a memory access), allowing greater overall utilization of the available resources. The Fundamental Computer System | 3
  • 30.
    Finally, and mostimportant for the higher-level programmer, there is the prevalence of multicore architectures. These architectures include multiple CPUs within the same unit, which increases the total capability without running into barriers to mak‐ ing each individual unit faster. This is why it is currently hard to find any machine with fewer than two cores—in this case, the computer has two physical computing units that are connected to each other. While this increases the total number of oper‐ ations that can be done per second, it can make writing code more difficult! Figure 1-1. Clock speed of CPUs over time (from CPU DB) Simply adding more cores to a CPU does not always speed up a program’s execution time. This is because of something known as Amdahl’s law. Simply stated, Amdahl’s law is this: if a program designed to run on multiple cores has some subroutines that must run on one core, this will be the limitation for the maximum speedup that can be achieved by allocating more cores. For example, if we had a survey we wanted one hundred people to fill out, and that survey took 1 minute to complete, we could complete this task in 100 minutes if we had one person asking the questions (i.e., this person goes to participant 1, asks the questions, waits for the responses, and then moves to participant 2). This method of having one person asking the questions and waiting for responses is similar to a serial process. In serial processes, we have operations being satisfied one at a time, each one waiting for the previous operation to complete. However, we could perform the survey in parallel if we had two people asking the questions, which would let us finish the process in only 50 minutes. This can be done 4 | Chapter 1: Understanding Performant Python
  • 31.
    because each individualperson asking the questions does not need to know anything about the other person asking questions. As a result, the task can easily be split up without having any dependency between the question askers. Adding more people asking the questions will give us more speedups, until we have one hundred people asking questions. At this point, the process would take 1 minute and would be limited simply by the time it takes a participant to answer questions. Adding more people asking questions will not result in any further speedups, because these extra people will have no tasks to perform—all the participants are already being asked questions! At this point, the only way to reduce the overall time to run the survey is to reduce the amount of time it takes for an individual survey, the serial portion of the problem, to complete. Similarly, with CPUs, we can add more cores that can perform various chunks of the computation as necessary until we reach a point where the bottleneck is the time it takes for a specific core to finish its task. In other words, the bottleneck in any parallel calculation is always the smaller serial tasks that are being spread out. Furthermore, a major hurdle with utilizing multiple cores in Python is Python’s use of a global interpreter lock (GIL). The GIL makes sure that a Python process can run only one instruction at a time, regardless of the number of cores it is currently using. This means that even though some Python code has access to multiple cores at a time, only one core is running a Python instruction at any given time. Using the pre‐ vious example of a survey, this would mean that even if we had 100 question askers, only one person could ask a question and listen to a response at a time. This effec‐ tively removes any sort of benefit from having multiple question askers! While this may seem like quite a hurdle, especially if the current trend in computing is to have multiple computing units rather than having faster ones, this problem can be avoided by using other standard library tools, like multiprocessing (Chapter 9), technologies like numpy or numexpr (Chapter 6), Cython (Chapter 7), or distributed models of computing (Chapter 10). Python 3.2 also saw a major rewrite of the GIL, which made the system much more nimble, alleviating many of the concerns around the system for single-thread performance. Although it still locks Python into running only one instruction at a time, the GIL now does better at switching between those instructions and doing so with less overhead. Memory Units Memory units in computers are used to store bits. These could be bits representing variables in your program or bits representing the pixels of an image. Thus, the abstraction of a memory unit applies to the registers in your motherboard as well as your RAM and hard drive. The one major difference between all of these types of The Fundamental Computer System | 5
  • 32.
    2 Speeds inthis section are from https://oreil.ly/pToi7. memory units is the speed at which they can read/write data. To make things more complicated, the read/write speed is heavily dependent on the way that data is being read. For example, most memory units perform much better when they read one large chunk of data as opposed to many small chunks (this is referred to as sequential read versus random data). If the data in these memory units is thought of as pages in a large book, this means that most memory units have better read/write speeds when going through the book page by page rather than constantly flipping from one ran‐ dom page to another. While this fact is generally true across all memory units, the amount that this affects each type is drastically different. In addition to the read/write speeds, memory units also have latency, which can be characterized as the time it takes the device to find the data that is being used. For a spinning hard drive, this latency can be high because the disk needs to physically spin up to speed and the read head must move to the right position. On the other hand, for RAM, this latency can be quite small because everything is solid state. Here is a short description of the various memory units that are commonly found inside a standard workstation, in order of read/write speeds:2 Spinning hard drive Long-term storage that persists even when the computer is shut down. Generally has slow read/write speeds because the disk must be physically spun and moved. Degraded performance with random access patterns but very large capacity (10 terabyte range). Solid-state hard drive Similar to a spinning hard drive, with faster read/write speeds but smaller capacity (1 terabyte range). RAM Used to store application code and data (such as any variables being used). Has fast read/write characteristics and performs well with random access patterns, but is generally limited in capacity (64 gigabyte range). L1/L2 cache Extremely fast read/write speeds. Data going to the CPU must go through here. Very small capacity (megabytes range). Figure 1-2 gives a graphic representation of the differences between these types of memory units by looking at the characteristics of currently available consumer hardware. 6 | Chapter 1: Understanding Performant Python
  • 33.
    A clearly visibletrend is that read/write speeds and capacity are inversely propor‐ tional—as we try to increase speed, capacity gets reduced. Because of this, many sys‐ tems implement a tiered approach to memory: data starts in its full state in the hard drive, part of it moves to RAM, and then a much smaller subset moves to the L1/L2 cache. This method of tiering enables programs to keep memory in different places depending on access speed requirements. When trying to optimize the memory pat‐ terns of a program, we are simply optimizing which data is placed where, how it is laid out (in order to increase the number of sequential reads), and how many times it is moved among the various locations. In addition, methods such as asynchronous I/O and preemptive caching provide ways to make sure that data is always where it needs to be without having to waste computing time—most of these processes can happen independently, while other calculations are being performed! Figure 1-2. Characteristic values for different types of memory units (values from February 2014) The Fundamental Computer System | 7
  • 34.
    Discovering Diverse ContentThrough Random Scribd Documents
  • 35.
    Everything that Iread with Harry, or that I talk over with him, has new meaning for me, or a new force. Why are we so careful to avoid pain? If it was a necessary part of the highest mortal experience, how can we ask that it may be left out from ours? And yet, on every new occasion, we strive to put from us the offered cross. Even while we say, "Thy will be done!" an inward hope entreats that will to be merciful. Such remonstrances with myself rose in me as I read. They did not prevent me from feeling a thrill of dread as this warning passed over my lips:—"Who shall say how soon God may draw us from our easy speculations and theories of suffering, to the practical experience of it? Who can tell how soon we may be called to the fiery trial?" I turned involuntarily to Harry. He, too, had heard a summons in these words. I read in his eyes the answer that came from his steady breast,—"My Father, I am here!" I felt my spirit lifted with the closing words,—"If we suffer with him, we shall also reign with him"; but there was no change in Harry's clear, prepared look. I have never known a faith so implicit as his. He does not ask after threats or promises; he only listens for commands. When the services were over, Hans came forward to say good-bye to the Doctor and Harry. He took a hand of each, and stood looking from one to the other. "We cannot spare you, Harry Dudley. We shall miss you, Doctor. Harry, when you are ready to set up your farm, come and take a look round you here again. We are good people, and love you. There will be land near in the market before long. Sooner should you have it than old Rasey. Think of it; we can talk things over, evenings." "You shall have your turn," he said to his boys, who were waiting, one on either side of him. "I am an old man, and leave-taking comes hard. Youth has many chances more." He gave his benediction, repeated a little rhyming German couplet,— a charm, perhaps, for a good journey,—and then turned away
  • 36.
    sturdily, went slowlyout of the door and down the steps, leaving Karl and Fritz to say their words of farewell. Karl spoke for both. What Fritz had in his heart to say he could not utter, for the tears would have come with it. At a quarter before twelve Harry brought down the russet knapsack, —brought down the little flower-press,—brought down the long umbrella. He transferred from the over-full knapsack to his own some packages of flowers. The flower-press would not enter either knapsack. The Doctor had it strapped on outside his. I watched these little arrangements, glad of the time they took. Harry helped the Doctor on with his pack. I would have done the same for Harry, but he was too quick for me. I adjusted the strap from which the green tin case hung, that I might do something for him. Doctor Borrow took a serious leave of my mother,—for this, at least, was a final one. But Harry would not have it so. The tears were gathering in her eyes. "You will see us again," he said, confidently. The Doctor shook his head. "You have made us too happy here for us not to wish that it might be so." But my mother accepted Harry's assurance. They looked round for Tabitha. She appeared from my mother's room, the door of which had been a little open. Both thanked her cordially for her kind cares. She gave them her good wishes, affectionately and solemnly, and disappeared again. "I shall not bid you good-bye," said the Doctor, yet taking my hand. "Only till the nineteenth," said Harry, clasping it as soon as the Doctor relinquished it. "Till the eighteenth," I mean; "till the eighteenth," he repeated, urgently. "Till the eighteenth," I answered.
  • 37.
    The Doctor mountedthe blue spectacles. This was the last act of preparation. The minute-hand was close upon the appointed moment. At the first stroke of twelve, they were on their way. I followed, slowly, as if the reluctance of my steps could hold back theirs. The gate closed behind them. The Doctor took at once his travelling gait and trudged straight on; but Harry turned and gave a glance to the house, to the barn, to the little patch of flowers,—to all the objects with which the week had made him familiar. Then his look fell upon me, who was waiting for it. He searched my face intently for an instant, and then, with a smile which made light of all but happy presentiments, waved me adieu, and hastened on to overtake the Doctor. I was glad it was not a working-day,—glad that I could go in and sit down by my mother, to talk over with her, or, silent, to think over with her, the scenes which had animated our little room, and which were still to animate it. Harry's parting look stayed with me. I felt all my gain, and had no more sense of loss. Can we ever really lose what we have ever really possessed? Evening. I have been over to Blanty's. I should have gone yesterday, but it rained heavily from early morning until after dark. Such days I consider yours. I had been anxious about Blanty since Sunday, and not altogether without reason. He has had a threatening of fever. I hope it will prove a false alarm. I found him sitting at his door, already better,—but still a good deal cast down, for he was never ill in his life before. He had been wishing for me, and would have sent to me, if I had not gone. He could hardly let me come away, but pressed me to stay one hour longer, one half hour, one quarter. But I had some things to attend to at home, and, as he did not really need me, I bade him good-bye resolutely, promising to go to him again next Monday. I cannot well go sooner.
  • 38.
    If I hadstayed, I should have missed a visit from Frederic Harvey. When I came within sight of our gate, on the way back, a horseman was waiting at it, looking up the road, as if watching for me. He darted forward, on my appearance,—stopped short, when close beside me,—dismounted, and greeted me with a warmth which I blamed myself for finding it hard to return. He did not blame me, apparently. Perhaps he ascribes the want he may feel in my manner to New-England reserve; or perhaps he feels no want. He is so assured of the value of his regard, that he takes full reciprocity for granted. The docile horse, at a sign, turned and walked along beside us to the gate, followed us along the path to the house, and took his quiet stand before the door when we went in. Frederic Harvey, having paid his respects to my mother, seated himself in the great arm-chair, which now seems to be always claiming the Doctor, and which this new, slender occupant filled very inadequately. "I stayed in New York three weeks too long," he exclaimed, after looking about him a little—for traces of Harry, it seemed. "Time goes so fast there! But I thought, from one of my sister's letters, that Dudley was to go back to World's End after he left you. Is he changed? Oh, but you cannot tell. You never knew him till now. I need not have asked, at any rate. He is not one to change. While I knew him, he was only more himself with every year." "It is two years since you met, is it not?" "Yes; but what are two years to men who were children together? We shall take things up just where we laid them down. Ours is the older friendship. I shall always have the advantage of you there. But you and he must have got along very well together. Your notions agree with his better than mine do. It does not matter. Friendship goes by fate, I believe. He may hold what opinions he likes, for me; and so may you."
  • 39.
    "I believe thaton some important subjects my opinions differ very much from yours."—I am determined to stand square with Frederic Harvey. "In regard to our institutions, you mean? I know, that, spoken or unspoken, hatred of them is carried in the heart of every New- Englander. It is sometimes suppressed through politeness or from interest, but I never saw a Northerner who was good for anything, in whom it did not break out on the first provocation. I like as well to have it fairly understood in the outset. I have had a letter from Harry in answer to one of mine. It is explicit on this point." I had no doubt it was very explicit. Frederic's eye meeting mine, he caught my thought, and we had a good laugh together, which made us better friends. "The Northerners are brought up in their set of prejudices, as we in ours. I can judge of the force of theirs by that of my own. I only wish there was the same unanimity among us. We are a house divided against itself." And Frederic's face darkened,—perhaps with the recollection of the rupture of old ties in Shaler's case,—or rather, as it seemed, with the rankling of some later, nearer pain. He turned quickly away from the intrusive thought, whatever it was. He does not like the unpleasant side of things. "At any rate, because Harry Dudley and I are to be adverse, it does not follow that we are to be estranged. I cannot forget our school- days,—our walks on the boulevards and the quays,—our rides in the Bois,—our journeys together, when we were like brothers. I was never so happy as in those days, when I had not a care or a duty in the world." He had the air, with his twenty-one years, of a weary man-of-the- world. There was no affectation in it. Unless report have done him injustice, the last two years have put a gulf between him and that time.
  • 40.
    I reminded himof the conversation between him and his sister, in which they spoke of Harry Dudley before I knew who Harry Dudley was. He remembered it, and returned very readily to the subject of it. He related many incidents of the tour in Brittany, and spoke warmly of the pleasure of travelling with a companion who is alive to everything of interest in every sort. He said his travels in Germany, and even in Italy, had hardly left with him so lively and enduring impressions as this little journey into Brittany; for there he had gone to the heart of things. "I must see him again. We must meet once more as we used to meet. We must have one good clasp of the hand; we must, at least, say a kind good-bye to the old friendship. If, hereafter, we find ourselves opposed in public life, I shall deal him the worst I can, but with openness and loyalty like his own, and doing him more justice in my heart, perhaps, than he will do me." Frederic Harvey inquired anxiously where Harry was to be found, and I was obliged to tell him of our intended meeting. I was afraid he would propose to go with me. He was on the point of doing so, but refrained, seeing that I was not expecting such a suggestion. We could easily have arranged to meet at Quickster, which is about the same distance from him that it is from me. But a ride of twenty miles, most of them slow ones, beside a man with whom you are not in full sympathy, is a trial. I did not feel called upon to undergo it for him. When he took leave of me, he again seemed about to propose something, and I felt it was this plan which was so natural; but he was again withheld, by pride or by delicacy. Either feeling I could sympathize with, and I was more touched by this reserve than by all his friendly advances; but I hardened my heart. He mounted his horse. I saw him go slowly down the path to the road, stoop from the saddle to open the gate,—pass out. And then I was seized with sudden compunction. I heard the slow step of his horse, receding as if reluctantly, and ready to be checked at a hint. I ran to the gate. Frederic was just turning away, as if he had been looking back,
  • 41.
    expecting to seeme; but in the same instant he gave an intimation to his horse, and was out of the reach of my repentance. "I liked him." With Harry these words mean a great deal. Could Harry ever have liked him, if he had not been worthy to be liked? How sad his look was, when he spoke of his happy boyish days!— happier than these only because they were blameless. Was not this regret itself an earnest of the power of return? He had good blood in him. He is Charles Shaler's cousin. He has a weak, shallow mother,— a father whose good qualities and whose faults are overlaid with the same worldly varnish impartially. He feels the need of other influences, and clings to Harry. He comes to me instinctively seeking something he has not in his home. My mother has always judged him more kindly than I have. If he had been a poor outcast child, I should have felt his coming to me so frankly and so persistently to be a sign I was to do something for him. Is there a greater need than that of sympathy and honest counsel? I have been selfish, but this pain is punishment enough. I feel a remorse surely out of proportion to my sin. I do not prevent his going to meet Harry by not asking him to go with me. He is not one to give up his wish; and in this case there is no reason that he should. He will arrive; I am sure of it. And I will atone, at least in part. I will ask him to join me on the ride home. Old Jasper has told me stories of Frederic Harvey's good- heartedness in childhood: tells them to me, indeed, every time he sees me. I remember one in particular, of the pretty little boy in his foreign dress, and speaking his foreign language, carrying his own breakfast one morning to the cabin where the old man lay sick; and another of his taking away part of her load from a feeble woman; and another of his falling on a driver and wresting from him the whip with which he was lashing a fainting boy. But Jasper has only these early stories to tell of him; and what different ones are current now! In dear old New England the child is father of the man. There the lovely infancy is the sure promise of the noble maturity. But where justice is illegal! where mercy is a criminal indulgence! where youth
  • 42.
    is disciplined toselfishness, and the man's first duty is to deny himself his virtues! If the nephew of Augustus had lived, would he indeed have been Marcellus? Heu pietas! Heu prisca fides!—these might have been mourned, though Octavia had not wept her son. Thursday, April 18, 1844. It is thirty-five miles to Omocqua by the common road through Metapora and Tenpinville; but I shall save myself five, going across fields and through wood-paths, and coming out at Quickster. You left the Omocqua road there, and took that to Quarleston. I shall stop half an hour at Quickster to rest my horse and have a little talk with Barton. I mean to allow myself ample time for the journey, that Brownie may take it easily and yet bring me to Omocqua in season for a stroll about the neighborhood with the Doctor and Harry before nightfall. Some miles of my way are difficult with tree-stumps and brush; a part of it is sandy; the last third is hilly. I have never been farther on that road than Ossian, about three miles beyond Quickster; but the country between Ossian and Omocqua is, I know, very much like that between Quarleston and Cyclops, which you found so beautiful and so tiresome. I do not mean that my parting with Harry shall be a sad one. After that day at Omocqua, I shall not meet his smile,—his hand will not clasp mine again; but he will leave with me something of himself which will not go from me. His courage, the energy of his straightforward will, shall still nerve and brace me, though his cordial voice may never again convey their influence to my heart. Wherever he is, I shall know we are thinking, feeling together, and working together; for I shall surely do what he asks of me: that he thinks it worth doing is enough. And Dr. Borrow does not leave me what he found me. It was with a continual surprise that I learned how much there is of interest and
  • 43.
    variety in ouruniform neighborhood for a man who knows the meaning of what he sees. How many things are full of suggestion now that were mute before! He has given me glimpses of undreamed-of pleasures. A practical man, following him in his walks, and gathering up the hints he lets fall, might turn them to great real use. What a part the Doctor and such as he, disciples and interpreters of Nature, would have in the world, how warmly they would be welcomed everywhere, if these were only times in which men could live as they were meant to live, happy and diligent, cherishing Earth and adorning her, receiving her daily needful gifts, and from time to time coming upon precious ones, which she, fond and wise mother, has kept back for the surprise of some hour of minuter search or bolder divination! But now, how can we be at ease to enjoy our own lot, however pleasantly it may have been cast for us, or to occupy ourselves with material cares or works, even the most worthy and the most rational? We are taught to pray, "Thy kingdom come," before we ask for our daily bread. To pray for what we do not at the same time strive for, is it not an impiety? Dr. Borrow says that Harry is out of place in our time. I should rather say that it is he himself who is here a century, or perhaps only a half-century, too soon. Our first need now is of men clear-sighted to moral truths, and intrepid to announce and maintain them. It was through the consciousness, not yet lost, of eternal principles, that primitive poetry made Themis the mother of the gracious Hours, —those beneficent guardians, bringers of good gifts, promoters and rewarders of man's happy labor. When Justice returns to make her reign on earth, with her come back her lovely daughters, and all the beautiful attendant train.
  • 44.
    When that timearrives, the Doctor will have found his place, and Harry will not have lost his. Perhaps I shall not come back until Saturday. According to their plan, Dr. Borrow and Harry are to leave Omocqua again to-morrow afternoon; but I shall try to persuade them to remain until the next morning. While they stay, I shall stay. When they go, Brownie and I take our homeward road. In any case, I will write to you Friday night, and send off my budget on Saturday without fail. To-day has not given me anything to tell of it yet, except that it has opened as it should, fresh and cloudless. In five hours I shall be on the road. My paper is blistered and the writing blurred with wet drops. It is only that some freshly gathered flowers on my table have let fall their dew upon the page. You, with the trace of mysticism that lurks in your man of the world's heart, would be drawing unfavorable auguries. I am too happy to accept any to-day. If fancy will sport with this accident, let it feign that these morning tears are of sympathy, but not of compassion; that they fall, not to dim my hopes, but to hallow them. Evening. "In five hours I shall be on the road." So I wrote at six o'clock. I wrote too confidently. At eleven I had mounted my horse, had sent my last good-bye through the open window, and had caught the last soft answer from within. I lingered yet an instant, held by those links of tenderness and solicitude that bind to home and make the moment of parting for any unusual absence, even though a pleasant and desired one, a moment of effort. A heavy, dragging step, which I almost knew before I saw the lounging figure of Phil Phinn, warned me of a different delay. I watched his slow approach with a resignation which had still a little hope in it; but when he at last stood beside me and began his ingratiating preamble, I felt my sentence confirmed. His
  • 45.
    woe-begone face, hisquivering voice, announced the suppliant before he reached the recital of his wrongs; while the utter self- abandonment of his attitude conveyed renunciation of all cares and responsibilities in favor of his elected patron. I will not give you the details of the difficulty of to-day,—an absurd and paltry one, yet capable of serious consequences to him. I obeyed instinctively the old-fashioned New-England principle I was brought up in, which requires us to postpone the desire of the moment to its demands. Sadly I led my horse to the stable, took off the saddle and put him up. "I cannot be back until two," I thought, "perhaps not before three. I shall lose our walk and our sunset; but even if it is as late as four, I will still go." I ran into the house to say a word of explanation to my mother; but she had heard and understood. She gave me a look of sympathy, and I did not wait for more. I set out resolutely in a direction opposite to that in which my own road lay. Phil Phinn followed, already raised to complacency, though not to energy. I outwalked him continually, and was obliged to stop and wait for him to come up. He plainly thought my haste unseasonable, and did not disguise that he was incommoded by the sun and the mud. It was a tedious way, a long five miles for him and for me. We arrived at last at the house of his adversary, who, having, besides the advantage of being in a superior position, also that of justice on his side, could the more easily give way. I should soon have come to an understanding with him, if my client, while leaving me the whole responsibility of his case, had not found himself unable to resign its management: he must lend me the aid of his argumentative and persuasive gifts. After some hours of wrangling and pleading, the matter was accommodated, and Phil Phinn, without a care in the world, or the apprehension of ever having one again, sauntered away toward his home. I set off for mine, already doubtful of myself, remembering that I was not the only disappointed one.
  • 46.
    When I reachedhome, it was half-past six o'clock. I felt strongly impelled to go, even then. My mother did not offer any objection, but her look showed so plainly the anxiety the thought of a night- ride caused her, that I gave it up without a word. I could not, indeed, have arrived at Omocqua before midnight, and Harry would long have done expecting me. I am not as well satisfied with myself as I ought to be, having made such a sacrifice to duty. I begin to ask myself, Was it made to duty? After all, a little suspense would have done Phil Phinn good,—if anything can do him good. And are not the claims of friendship paramount to all other? Harry will be pained by needless anxiety. Can he believe that I would, without grave cause, lose any of the time we might yet have together? But a few hours will set all right. Friday Night, April 19. I am at home again. I take out the package which has been waiting for the day at Omocqua. Hoarding is always imprudence. If these letters of last week had gone on their day, they would have been faithful messengers. Now they go to tell you of a happiness which already is not mine,—of hopes and plans that you can never share. Are these last pages yesterday's? A lifetime is between me and them. The book I pushed aside to write them lies there open, waiting to be recalled. Had it an interest for me only yesterday? The flowers on my table still hold their frail, transient beauty. No longer ago than when I gathered them, I could take pleasure in flowers! I sit here and go through the history of these last two days, retracing every minutest incident. I begin again. I make some one little circumstance different, and with it all is changed. I pass into a happy dream; I find myself smiling. And then I remember that I cannot smile!
  • 47.
    I was towrite to you to-night. I should have written, if I had not promised. I must spend these hours with you. Every object here is so full of pain! Everything is so exactly as it was; and yet nothing can ever be as it was to me again! It seemed last evening that I suffered more from my disappointment than was reasonable. I wished for sleep to shorten the hours of waiting. But troubled dreams lengthened them instead. I was up at three; at four I was on the road. I had an hour over fields and cleared land; then came some miles through the woods. The forest- ride had not its usual charm. I was still haunted by the failure of yesterday. I could not bear the thought of being misjudged by Harry, even for a moment. I longed to be with him and explain. But would he find me absolved? I was glad to come out into light and cheerfulness at Quickster. It was six o'clock when I stood before the door of the Rapid Run. Barton came down to me, drew out his pocket-book, and took from it a folded paper. "Here is something of yours." I opened it and found written in pencil,—"Jackson House, Omocqua." The sight of that frank handwriting dispelled every doubt. "When was he here?" "He came in a little before one yesterday. He asked if you had been along. I thought not; you would have given me a call. He stayed round here about an hour, waiting for you. I told him that you might have struck the road farther down,—at Ossian, perhaps. He took a horse of me, knowing you would ride." "He was alone?" "Yes. He told me Dr. Borrow was at Rentree; was to join him at Omocqua this morning, though." In half an hour we were on our way again. I was eager still, but no longer impatient. There was no uncertainty in my mind now. Harry
  • 48.
    was at Omocqua.He was expecting me. As to blaming me, he had never thought of it. He would have imagined for me some better excuse than I had to give. Or rather, it had never occurred to him that I could need excuse. I should find him at the door on the lookout for me. His hand would be in mine before I could dismount. In the mean while the miles between us diminished rapidly. My horse enjoyed, as I did, every step of the happy road. His prompt, elastic tread showed it, and the alert ears which seemed not watchful against danger, but vigilant to catch all the sweet and animating sounds that cheered us forward. Three miles from Quickster we came on the intended town of Ossian. I stopped a moment. Harry had probably lingered here yesterday, watching to see me emerge from that dusky wood-path. He had found no one to speak to. One inhabitant outstayed the rest a year; but he has now been long gone, and his house is falling in. Beyond Ossian the road was new to me. For about three miles it is good. Then the country becomes uneven, and soon after very hilly. It was slower work here; but Brownie and I took it pleasantly. "How far is it to Omocqua?" I asked, as he was passing me, a man whom I had watched painfully descending in his little wagon the hill I was about to climb. He drew up at once. "Omocqua? You are for Omocqua? An hour, or a little more; though I am a good hour and a half from there. They had something of a fuss down there last night, perhaps you know." "What about?" "Well, a man from Tenpinville met a runaway boy of his who had been hiding round there. The fellow ran; his master hailed him, and when he wouldn't stop, out with a pistol and shot him flat." "What was the man's name?"
  • 49.
    "If I heard,I've lost it. I put up just outside the town. If I'd gone in to hear the talk, I might have got mixed up; and I'd no call." The hour was a long one. I hardly wished it shorter, yet I tried to hasten. I urged my horse; but mastery is of the spirit, not of the hand or will. He had obeyed so well the unconscious impulse! and now, though he started forward under the spur of an inciting word, he soon forgot it, and mounted the slow hills and descended them again with drudging step and listless ears. What a meeting! what a topic for the nineteenth of April! I imagined Harry's grief, his shame, his concentrated indignation. I remembered the flash of his eye, the flush of his cheek, when Dr. Borrow was telling of the approach of the slave-coffle from which they had rescued Orphy. And with this a keen apprehension seized me. Would Harry have been able to repress his remonstrance, his reprobation? The common man I had just met had not trusted the acquired prudence of half a century. Could Harry's warm young heart contain itself? Why was I not there? A warning, a restraining word——. But would Harry have heard it? Could I have spoken it? Would he not have felt, must not I have felt with him, that this was one of those moments when to see wrong done without protesting is to share in it? And then rose before me the possible scenes:—the beautiful, glowing face, the noble, passionate words, the tumult, the clamor, the scoff, the threat, the—— Oh, no! surely the angels would have had charge concerning him! When we reached the summit of the last hill, my horse stopped of himself, as if to let me receive well into my mind the first lovely aspect of the town below us, and thus connect a charm with its name which nearer knowledge should not be able to disturb. I yielded to the influence of the scene the more easily that it was in such contrast with my perturbed feelings. We may court and cherish a fanciful or a superficial grief; but the bitterly tormented mind asks
  • 50.
    ease as thetortured body does, and takes eagerly the soothing draught from any hand. The landscape, still freshened by the night, and already brilliant with the day, spoke peace and hope. I accepted the promise. Descending the hill, I thought and reasoned cheerfully. I smiled that I should have fancied nothing could happen in Omocqua, when Harry was there, without his having a part in it. This took place last evening; he had not heard of it yet, perhaps. Or he had heard of it; but not until it was over, and there was nothing to be done. He was commonly silent under strong emotion. He would have heard this story as he had heard others of the sort, with resolved composure, finding in it new food for his inward purpose. On the outskirts of the town I came to a little tavern, the one probably at which my acquaintance of the road had lodged. I had almost stopped to ask the news, but thought better of it, and was going on, when a man sitting on a bench under a tree started up and ran after me, shouting. I stopped, and he came up out of breath. "You thought we were shut, seeing us so still; but we're all on hand." I explained, that I was going to the Jackson House, where a friend was to meet me. "The Jackson House! That's head-quarters for news, just now. All right. You looked as if you wanted to stop." "I thought of stopping for a moment. I heard on the road that there had been some sort of disturbance in your town yesterday. Is all quiet now?" "For aught I know." "I heard there was a boy shot here yesterday." "A boy?" "A runaway."
  • 51.
    "One of ourwaiters brought down such a story last night. They are sharp after news of their own. I told him 'twas wholesome, if it turned out so. But this morning it comes that it was the man who was running him off that was shot. You'll hear all about it at the Jackson. If you come back this way, stop and give me a word. I can't leave." There were a number of men on the piazza of the Jackson House. Most of them had the air of habitual loungers; a few were evidently travellers newly arrived. Not a figure that even from a distance I could take for Harry Dudley. Some trunks and valises were waiting to be carried in, but I saw nothing familiar. I recognized the landlord in a man who was leaning against a pillar, smoking. He did not come forward, or even raise his eyes, when I rode up. I bade him good- morning, addressing him by name. He came forward a little,—bowed in answer to my salutation, but did not speak. "Is Mr. Dudley here?" Brompton did not reply. He threw out two or three puffs of smoke, then took the cigar from his lips and flung it from him. He looked serious, and, I thought, displeased. My misgivings returned. Had Harry incurred ill-will by some generous imprudence? Had he left the house, perhaps? Was the landlord afraid of being involved in his guest's discredit? He spoke at last, with effort. "Is your name——?" "Colvil." He came down the steps and stood close to me, laying a hand on my horse's neck and stroking down his mane. "Mr. Colvil, I don't know that anybody is to blame; but an accident has happened here. I'm sorry to be the one to tell you of it."
  • 52.
    I dismounted. Bromptonmade several attempts at beginning, but stopped again. "You had some trouble in your town yesterday," I said; "can that in any way concern Mr. Dudley?" "Are you a near friend of his?" "Yes." "A relation?" "No." He went on with more assurance. "Mr. Dudley was here about a month ago. He had a sick boy with him, whom he left here, in a manner under my care. He was to have taken him away to-day. He arrived yesterday afternoon and asked me to send for the boy. I sent for him. Mr. Dudley was expecting you yesterday afternoon, and walked over to the Jefferson to see if there was any mistake. "The boy was his. It was all regular. He had him of Ruffin, who never does anything unhandsome. I knew all about it. Ruffin was here with a lot of all sorts he had been picking up round the country. He told me to keep the boy pretty close while I had him in charge; and I boarded him outside the town, with an old granny, who didn't know but he was really in hiding. But it was all right. He was a pet servant, spoiled till he grew saucy, and his master swapped him off,—but quietly, the family set so much by the boy. They were to think he'd been enticed away. But it must happen, that, exactly yesterday afternoon, one of the sons came riding up to this very house. He left his horse to the servant he brought with him; then comes up to the door and asks if Mr. Dudley is here; hears that he has walked out, and so walks out too. The first thing he meets, just out here on the square, is this boy, whom he had been fond of, and only over-kind to. The boy checks up, and then, like a fool, turns and runs. The young man calls to him to stop,—and then, to stop or he'd shoot.
  • 53.
    The boy onlyruns faster. Dudley was crossing the square, on his way back from the Jefferson, and came up at the moment. He told Orphy to stand still, and, stepping right between him and the levelled pistol, called to the other to hold on. But the man was so mad with rage at seeing his servant flout him and mind another, that he could not stop his hand. I was standing where you are now. I saw Dudley come up, with his even step, just as usual. I heard his voice, clear and cool. I did not look for mischief until I heard the crack of the pistol,—and there he was on the ground! I ran down to him. I was going to have him taken into the house, but he wanted to lie in the open air. We carried him round to the green behind the barn. There was an army-surgeon here, on his way West. He did what he could, but said it was only a question of hours. Dudley knew it. He wanted to keep on till morning, thinking you might come. He lasted till after daybreak. Will you go to him?" I followed Brompton into the house, along the entry, across the yard, through the great barn. A road led from a gate on a side-street to a shed. Before us, on the other side of the road, was a green field with one great tree. The grass under the tree was flattened. "Yes, it was there," said Brompton. "He asked to be laid under that tree. The sun was just setting over there. When evening came, we wanted to take him to the house; but no. We let him have his will. It was natural he should want to see the sky while he could." Brompton led the way to the shed. What struggles must have rent that strong young breast before the life was dislodged from it! How must the spirit which had known this earth only through innocent joys and sweet affections and lovely hopes,—how must it have clung to its dear mortal dwelling-place! how mourned its dividing ties! how claimed its work, unfinished, unbegun! This grief, this yearning, this reluctance would have left their story on the cold immovable face. With these, bodily torture would have done its part to alter and impair! I followed my guide,
  • 54.
    foreboding that thedumb anguish in my heart was to be displaced by a fiercer pain. There was no pain in his presence. In death, as in life, he kept his own gift of blessing. The holy light still lay on the brow; about the lips hovered a smile, last ethereal trace of the ascended spirit. My soul lifted itself to his. I understood the peace that passeth understanding. An angry voice brought me back to the world and its discords. "Do you think you were worth it?" I looked where Brompton was looking, and saw, seated near, on an overturned barrel, a figure which could be no other than that of Orphy. He sat impassive. Brompton's cruel words had not reached him. His misery was its own shield. His utter wretchedness precluded more. But he felt my look fixed upon him. He raised his eyes to me for a moment, then closed them again to shut himself in with his woe. And now his face quivered all over; his lips parted and closed rapidly,—not as forming articulate accents, but in the helpless forlornness that has no language in which to utter plaint or appeal. And yet on these trembling cheeks, about this inane mouth, still lingered some of the soft, playful lines I remembered on the pretty, varying face of little Airy Harvey! On the way from the house I was conscious that a step followed us, stopping when we stopped, and going on again when we did; but I had not given thought to it until now, when I perceived a timid movement behind me, and felt a light touch laid on my arm. I turned, and met a pair of mournful, pleading eyes. "Jasper!" The old man stretched one trembling hand toward the dead, while the other clasped my wrist.—"It was not meant! It was not meant!" "It was not," said Brompton.
  • 55.
    "Do not bearanger! He did not." "He did not," echoed Brompton. Jasper, searching my face, saw there what changed his look of entreaty into one of compassion. He stroked my sleeve soothingly with his poor shrunken fingers.—"And yet there never was anything but love between you! Oh, think there is a sorer heart than yours this day!" "Where is he?" I asked, fearing lest that most unhappy one might be near. "Gone."—It was Brompton who answered.—"Gone, I believe. He was here until all was over. He locked himself into a room up-stairs. Dudley sent for him many times the night through, in the intervals of his pain. I took the messages to him. But he could neither bear to see the one he had killed, nor yet to go away, and have no chance of seeing him again. At daybreak Dudley got up, saying he had strength enough, and went as far as the barn on his way to the house. There the surgeon met him and led him back, pledging his word that the man should be brought, if it was by force. And it was almost by force, but he was brought. Dudley raised himself a little, when he came up, took his hand and clasped it close. 'Good-bye, Fred!'—in a pleasant voice, as if he were ready for a journey and must cheer up the friend he was to leave behind. And then he sank back, still holding the other's hand, and looking up at him with his kind eyes, not forgiving, but loving,—till the eyelids drooped and closed softly, and he passed into a quiet sleep. When we left him, he was breathing gently. We thought it was rest." Jasper went humbly away, secure of his suit. Brompton, too, withdrew silently.
  • 56.
    In those firstmoments I had left below my loss and my grief to follow the ascended; but now my human heart asked after the human friend. On the rich, disordered hair were signs of the mortal agony: the soft, bright curls were loosened and dimmed. The pure forehead could not be fairer than it was, yet the even, delicately finished eyebrows seemed more strongly marked. The brown eyelashes showed long and dark over the white cheek. The same noble serenity; the same gentle strength; only the resolute lines about the mouth were softened;—nothing now to resist or to dare! Dr. Borrow would be here soon. I sat down on a block and waited. Dr. Borrow! I had thought his love for Harry tinctured with worldliness; but how honest and hearty it appeared to me now! I had loved in Harry Dudley what he was to be, what he was to do. Dr. Borrow had loved him for himself only, simply and sincerely. I remembered the Doctor's misgivings, his cautions to me. How negligently heard! Then it was only that he did not yet comprehend the high calling of the boy whom we equally loved. Now I almost felt as if I had a complicity in his fate,—as if the Doctor could demand account of me. That Harry Dudley would give himself to a great cause had been my hope and faith; that he would spend himself on a chimera had been Doctor Borrow's dread. But which of us had looked forward to this utter waste? How reconcile it with Divine Omnipotence? with Supreme Justice? Was there not here frustration of a master-work? Was there not here a promise unfulfilled? Careless footsteps and voices gave notice of the approach of men brought by curiosity. Seeing me, and judging me not one of themselves, they stop outside, confer a moment in lower tones, come in singly, look, and go out again. Then new voices. A tall, stout man stalked heavily in. "And the boy was his own, after all," burst from him as he rejoined the others.
  • 57.
    "The boy wasnot his own. He didn't buy him fairly to keep and work him. It was a sham sale. He meant to free him from the first, and the boy knew it. He was free by intention and in fact. He had all the mischief in him of a free negro." "The man was a New-Englander, and saw it differently," answered the first voice. "A man is not a fool because he is a New-Englander," replied the second. "I am from New England myself." "I don't see much of the same about you. Are there more there like him or like you?" "I tell you he has died as the fool dieth," the other answered sharply, coming carelessly in as he spoke. He was a mean-looking man, trimly dressed, in whom I could not but recognize the Yankee schoolmaster. As he stooped down over the man he had contemned, some dormant inheritance of manhood revealed itself in his breast, some lingering trace of richer blood stirred in his dull veins. He turned away, cast towards me a humble, deprecating look, and, still bending forward, went out on tiptoe. Then, accompanied by a sweeping and a rustling, came a light step, but a decided, and, I felt, an indifferent one. A woman came in. She took account with imperious eyes of every object,—of me, of Orphy, of the coarse bench spread with hay, which served as bier,—and then walked confidently and coldly forward to the spectacle of death. When she had sight of the beautiful young face, she uttered a cry, then burst into passionate sobs, which she silenced as suddenly, turned, shook her fist at Orphy, and was gone. "Dr. Borrow is come." Come! To what a different appointment!
  • 58.
    "He asked foryou," persisted Brompton, seeing that I did not rise. "He is in the same room he had when they were here together. He mistrusted something, or he had heard something; he said no word until he was there. Then he asked me what he had got to be told, and I told him." I made a sign that I would go. Brompton left me with a look which showed that he knew what a part I had before me. Dr. Borrow was not a patient man. He was ruffled by a slight contrariety. This unimagined grief, how was it to be borne? With what words would he receive me? Would he even spare Harry Dudley himself, in the reproaches which his love would only make more bitter? We three were to have met to-day. Was he the one to be wanting? he who was never wanting? He who had been the life, the joy, of those dearly remembered hours, was he to be the sorrow, the burden of these? I went to him again; again earth and its anxieties vanished from me. No, he would not be wanting to us. When I touched the handle of the door, it was turned from the inside. Dr. Borrow seized my hand, clasping it, not in greeting, but like one who clings for succor. He searched my face with ardently questioning look, as if I might have brought him mercy or reprieve. He saw that I had not. A spasm passed over his face. His mouth opened to speak, with voiceless effort. He motioned me to lead where he was to go. We went down-stairs, and he followed me, as I had followed Brompton, along the entry, across the yard, through the barn. He glanced towards the tree and then took his way to the shed. I did not enter with him. When he came back to me, he was very pale, but his expression was soft and tender as I had never known it. We went in again together, and stood there side by side.
  • 59.
    Brompton spoke fromwithout. "There is one thing I have not told you, Dr. Borrow." The Doctor turned to him patiently. "There was an inquest held early this morning." Dr. Borrow lifted his hand to ward off more. "Let me take my child and go!" The Doctor looked towards Orphy. Again I had almost wronged him in my thought. "Come, my lad," he said, kindly; "you and I must take care of him home." Orphy left his place of watch. He came and stood close beside the Doctor, devoting his allegiance; tears gathered in the eyes that the soul looked through once more; the mouth retook its own pathetic smile. I knew that Harry Dudley must lie in Massachusetts ground, but I could not look my last so soon. Dr. Borrow saw my intention and prevented it. He took my hand affectionately, yet as holding me from him. "Do not come. I am better off without you. I must battle this out alone." Then, a moment after, as feeling he had amends to make,— "You have known him a few weeks. Think what I have lost,—the child, the boy, the man! All my hopes were in him,—I did not myself know how wholly!" And beyond this anguish lay other, that he would have put off till its time, but it pressed forward.
  • 60.
    "Colvil, you aregoing home. You go to be consoled. What am I going to?" On the side-street, the swift tread of horses and the roll of rapid wheels. A wagon stopped before the gate. What a joy Charles Shaler's coming was to have been to us! He was prepared. He came forward erect and stern. He saluted us gravely in passing, went in and stood beside the bier. He remained gazing intently for a little time,—then, laying his hand lightly on the sacred forehead, raised his look to heaven. He came out composed as he had entered. Shaler spoke apart with Brompton, and returned to us. "You would leave this place as soon as possible?" he said to Dr. Borrow. "Yes." I had meant to combat the Doctor's desire that I should leave him,— not for my own sake, but because I thought he would need me; but I submitted now. Shaler would assume every care, and I saw that Dr. Borrow yielded himself up implicitly. The moment came. We lifted him reverently, Orphy propping with his weak hands the arm that had once lent him its strength. We carried him out into the sunshine he had loved, bright then as if it still shone for him. The wind ruffled the lifeless hair whose sparkling curls I had seen it caress so often. It is over. Over with the last meeting, the last parting. Over with that career in which I was to have lived, oh, how much more than in my
  • 61.
    Welcome to ourwebsite – the ideal destination for book lovers and knowledge seekers. With a mission to inspire endlessly, we offer a vast collection of books, ranging from classic literary works to specialized publications, self-development books, and children's literature. Each book is a new journey of discovery, expanding knowledge and enriching the soul of the reade Our website is not just a platform for buying books, but a bridge connecting readers to the timeless values of culture and wisdom. With an elegant, user-friendly interface and an intelligent search system, we are committed to providing a quick and convenient shopping experience. Additionally, our special promotions and home delivery services ensure that you save time and fully enjoy the joy of reading. Let us accompany you on the journey of exploring knowledge and personal growth! textbookfull.com