Repository: dask/dask

Issue:
`dask.async` always computes the entire dask
I'm confused that `dask.async` seems to compute the entire dask every time instead of only running the tasks necessary to create a key:

```
d = dict(x=(print, 'a'), y=(print, 'b'))
import dask.async
dask.async.get_sync(d, 'x')
```

This prints

```
b
a
```

Is this intended?
The `get` function from `dask.core` only executes the required tasks.



Discussion:

Resolving patch:
diff --git a/dask/array/core.py b/dask/array/core.py
--- a/dask/array/core.py
+++ b/dask/array/core.py
@@ -15,7 +15,7 @@
 import numpy as np
 from . import chunk
 from .slicing import slice_array, insert_many
-from ..utils import deepmap, ignoring
+from ..utils import deepmap, ignoring, repr_long_list
 from ..async import inline_functions
 from ..optimize import cull, inline
 from .optimization import optimize
@@ -586,8 +586,9 @@ def dtype(self):
             return self.compute().dtype
 
     def __repr__(self):
+        blockdims = '(' + ', '.join(map(repr_long_list, self.blockdims)) + ')'
         return ("dask.array<%s, shape=%s, blockdims=%s, dtype=%s>" %
-                (self.name, self.shape, self.blockdims, self._dtype))
+                (self.name, self.shape, blockdims, self._dtype))
 
     def _get_block(self, *args):
         return core.get(self.dask, (self.name,) + args)
@@ -596,6 +597,16 @@ def _get_block(self, *args):
     def ndim(self):
         return len(self.shape)
 
+    @property
+    def size(self):
+        """ Number of elements in array """
+        return np.prod(self.shape)
+
+    @property
+    def nbytes(self):
+        """ Number of bytes in array """
+        return self.size * self.dtype.itemsize
+
     def _keys(self, *args):
         if self.ndim == 0:
             return [(self.name,)]
diff --git a/dask/async.py b/dask/async.py
--- a/dask/async.py
+++ b/dask/async.py
@@ -372,6 +372,15 @@ def get_async(apply_async, num_workers, dsk, result, cache=None,
                 **kwargs):
     """ Asynchronous get function
 
+    This is a general version of various asynchronous schedulers for dask.  It
+    takes a an apply_async function as found on Pool objects to form a more
+    specific ``get`` method that walks through the dask array with parallel
+    workers, avoiding repeat computation and minimizing memory use.
+
+    This function evaluates the entire graph, regardless of the given output
+    keys.  You may want to cull your graph ahead of time with
+    ``dask.optimize.cull``.
+
     Parameters
     ----------
 


Test patch:
diff --git a/dask/array/tests/test_array_core.py b/dask/array/tests/test_array_core.py
--- a/dask/array/tests/test_array_core.py
+++ b/dask/array/tests/test_array_core.py
@@ -539,6 +539,8 @@ def test_repr():
     assert str(d.shape) in repr(d)
     assert str(d.blockdims) in repr(d)
     assert str(d._dtype) in repr(d)
+    d = da.ones((4000, 4), blockshape=(4, 2))
+    assert len(str(d)) < 1000
 
 
 def test_slicing_with_ellipsis():
@@ -843,3 +845,13 @@ def test_squeeze():
     assert eq(x.squeeze(), x.compute().squeeze())
 
     assert x.squeeze().blockdims == ((3, 3, 3, 1),)
+
+
+def test_size():
+    x = da.ones((10, 2), blockshape=(3, 1))
+    assert x.size == np.array(x).size
+
+
+def test_nbytes():
+    x = da.ones((10, 2), blockshape=(3, 1))
+    assert x.nbytes == np.array(x).nbytes