I'm not doubting that the CPU is at work, but there's still quite a lot of overhead. Even at two CPUs, the speedup is far from linear. I'm not fully convinced yet that offering and maintaining this in our codebase is worth so the effort. E.g. if you want to use OpenNLP, then it's suboptimal because you need to call out to a Java process. In that case, threads communicating with separate processes are more appropriate, so then we'd need a `backend` arg to tell the vectorizer to use threads instead of processes (although that's actually quite easy with the new joblib).

I'm a bit conservative because I've seen the `CountVectorizer` grow over the years. It got optimized heavily, but it has also accumulated a lot of interacting options and switches that cause users to scratch their head.

Aside: if you want to do lemmatization properly you need to POS tag first, but without that the lemmatizer is faster than the Porter stemmer (because it's written in C):

```python
>>> words = [ln.strip().decode('latin1') for ln in open("/usr/share/dict/words")]
>>> len(words)
99171
>>> from nltk import PorterStemmer, WordNetLemmatizer
>>> stem = PorterStemmer().stem
>>> lemmatize = WordNetLemmatizer().lemmatize
>>> %timeit map(stem, words)
1 loops, best of 3: 693 ms per loop
>>> %timeit map(lemmatize, words)
1 loops, best of 3: 422 ms per loop
```

The Snowball stemmer, interestingly, is much slower and clocks at >1s.