diff --git a/docs/_newsfragments/1492.newandimproved.rst b/docs/_newsfragments/1492.newandimproved.rst
new file mode 100644
index 0000000..86860b5
--- /dev/null
+++ b/docs/_newsfragments/1492.newandimproved.rst
@@ -0,0 +1,2 @@
+WSGI path decoding in :class:`falcon.Request` was optimized, and is now
+significantly faster than in Falcon 2.0.
diff --git a/falcon/cyutil/misc.pyx b/falcon/cyutil/misc.pyx
new file mode 100644
index 0000000..095dddd
--- /dev/null
+++ b/falcon/cyutil/misc.pyx
@@ -0,0 +1,40 @@
+# Copyright 2020 by Vytautas Liuolia.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+def isascii(unicode string not None):
+    """Return ``True`` if all characters in the string are ASCII.
+
+    ASCII characters have code points in the range U+0000-U+007F.
+
+    Note:
+        On Python 3.7+, this function is just aliased to ``str.isascii``.
+
+    This is a Cython fallback for older CPython versions. For longer strings,
+    it is slightly less performant than the built-in ``str.isascii``.
+
+    Args:
+        string (str): A string to test.
+
+    Returns:
+        ``True`` if all characters are ASCII, ``False`` otherwise.
+    """
+
+    cdef Py_UCS4 ch
+
+    for ch in string:
+        if ch > 0x007F:
+            return False
+
+    return True
diff --git a/falcon/request.py b/falcon/request.py
index 827aaaa..76c5da3 100644
--- a/falcon/request.py
+++ b/falcon/request.py
@@ -24,6 +24,7 @@ from falcon.forwarded import Forwarded  # NOQA
 from falcon.media import Handlers
 from falcon.util import json
 from falcon.util import structures
+from falcon.util.misc import isascii
 from falcon.util.uri import parse_host, parse_query_string
 from falcon.vendor import mimeparse
 
@@ -464,8 +465,11 @@ class Request:
         # ISO-8859-1, e.g.:
         #
         #   tunnelled_path = path.encode('utf-8').decode('iso-8859-1')
-        #
-        path = path.encode('iso-8859-1').decode('utf-8', 'replace')
+
+        # perf(vytas): Only decode the tunnelled path in case it is not ASCII.
+        #   For ASCII-strings, the below decoding chain is a no-op.
+        if not isascii(path):
+            path = path.encode('iso-8859-1').decode('utf-8', 'replace')
 
         if (self.options.strip_url_path_trailing_slash and
                 len(path) != 1 and path.endswith('/')):
diff --git a/falcon/util/misc.py b/falcon/util/misc.py
index 4eea6d6..2287e93 100644
--- a/falcon/util/misc.py
+++ b/falcon/util/misc.py
@@ -36,6 +36,11 @@ import warnings
 
 from falcon import status_codes
 
+try:
+    from falcon.cyutil.misc import isascii as _cy_isascii
+except ImportError:
+    _cy_isascii = None
+
 __all__ = (
     'is_python_func',
     'deprecated',
@@ -508,3 +513,31 @@ def deprecated_args(*, allowed_positional, is_method=True):
         return wraps
 
     return deprecated_args
+
+
+def _isascii(string):
+    """Return ``True`` if all characters in the string are ASCII.
+
+    ASCII characters have code points in the range U+0000-U+007F.
+
+    Note:
+        On Python 3.7+, this function is just aliased to ``str.isascii``.
+
+    This is a pure-Python fallback for older CPython (where Cython is
+    unavailable) and PyPy versions.
+
+    Args:
+        string (str): A string to test.
+
+    Returns:
+        ``True`` if all characters are ASCII, ``False`` otherwise.
+    """
+
+    try:
+        string.encode('ascii')
+        return True
+    except ValueError:
+        return False
+
+
+isascii = getattr(str, 'isascii', _cy_isascii or _isascii)

diff --git a/tests/test_utils.py b/tests/test_utils.py
index d393a09..c611c2c 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -498,6 +498,21 @@ class TestFalconUtils:
         with pytest.raises(ValueError):
             misc.secure_filename('')
 
+    @pytest.mark.parametrize('string,expected_ascii', [
+        ('', True),
+        ('/', True),
+        ('/api', True),
+        ('/data/items/something?query=apples%20and%20oranges', True),
+        ('/food?item=ð\x9f\x8d\x94', False),
+        ('\x00\x00\x7F\x00\x00\x7F\x00', True),
+        ('\x00\x00\x7F\x00\x00\x80\x00', False),
+    ])
+    def test_misc_isascii(self, string, expected_ascii):
+        if expected_ascii:
+            assert misc.isascii(string)
+        else:
+            assert not misc.isascii(string)
+
 
 @pytest.mark.parametrize(
     'protocol,method',

perf(Request): Short-circuit path encode/decode when possible
See if we can quickly determine if the following is required for a given path and short-circuit it when it is not (from `Request.__init__`):

```py
# PEP 3333 specifies that PATH_INFO variable are always
# "bytes tunneled as latin-1" and must be encoded back
path = path.encode('latin1').decode('utf-8', 'replace')
```

See also this section from `falcon/testing/helpers.py`:

```py
# NOTE(kgriffs): The decoded path may contain UTF-8 characters.
# But according to the WSGI spec, no strings can contain chars
# outside ISO-8859-1. Therefore, to reconcile the URI
# encoding standard that allows UTF-8 with the WSGI spec
# that does not, WSGI servers tunnel the string via
# ISO-8859-1. falcon.testing.create_environ() mimics this
# behavior, e.g.:
#
#   tunnelled_path = path.encode('utf-8').decode('iso-8859-1')
#
# falcon.Request does the following to reverse the process:
#
#   path = tunnelled_path.encode('iso-8859-1').decode('utf-8', 'replace')
#
path = path.encode('utf-8').decode('iso-8859-1')
```
tests/test_utils.py::TestFalconUtils::test_misc_isascii[-True] tests/test_utils.py::TestFalconUtils::test_misc_isascii[/-True] tests/test_utils.py::TestFalconUtils::test_misc_isascii[/api-True] tests/test_utils.py::TestFalconUtils::test_misc_isascii[/data/items/something?query=apples%20and%20oranges-True] tests/test_utils.py::TestFalconUtils::test_misc_isascii[/food?item=\xf0\x9f\x8d\x94-False] tests/test_utils.py::TestFalconUtils::test_misc_isascii[\x00\x00\x7f\x00\x00\x7f\x00-True] tests/test_utils.py::TestFalconUtils::test_misc_isascii[\x00\x00\x7f\x00\x00\x80\x00-False]
tests/test_utils.py::TestFalconUtils::test_http_now tests/test_utils.py::TestFalconUtils::test_dt_to_http tests/test_utils.py::TestFalconUtils::test_http_date_to_dt tests/test_utils.py::TestFalconUtils::test_pack_query_params_none tests/test_utils.py::TestFalconUtils::test_pack_query_params_one tests/test_utils.py::TestFalconUtils::test_pack_query_params_several tests/test_utils.py::TestFalconUtils::test_uri_encode tests/test_utils.py::TestFalconUtils::test_uri_encode_double tests/test_utils.py::TestFalconUtils::test_uri_encode_value tests/test_utils.py::TestFalconUtils::test_uri_decode tests/test_utils.py::TestFalconUtils::test_uri_decode_replace_bad_unicode[+%80- tests/test_utils.py::TestFalconUtils::test_uri_decode_replace_bad_unicode[+++%FF+++- tests/test_utils.py::TestFalconUtils::test_uri_decode_replace_bad_unicode[%fc%83%bf%bf%bf%bf-\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd] tests/test_utils.py::TestFalconUtils::test_uri_decode_replace_bad_unicode[%ed%ae%80%ed%b0%80-\ufffd\ufffd\ufffd\ufffd\ufffd\ufffd] tests/test_utils.py::TestFalconUtils::test_uri_decode_unquote_plus tests/test_utils.py::TestFalconUtils::test_prop_uri_encode_models_stdlib_quote tests/test_utils.py::TestFalconUtils::test_prop_uri_encode_value_models_stdlib_quote_safe_tilde tests/test_utils.py::TestFalconUtils::test_prop_uri_decode_models_stdlib_unquote_plus tests/test_utils.py::TestFalconUtils::test_unquote_string tests/test_utils.py::TestFalconUtils::test_parse_query_string tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[-True-expected0] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[-False-expected1] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[flag1&&&&&flag2&&&-True-expected2] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[flag1&&&&&flag2&&&-False-expected3] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[malformed=%FG%1%Hi%%%a-False-expected4] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[=-False-expected5] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[==-False-expected6] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[%==+==&&&&&&&&&%%==+=&&&&&&%0g%=%=-False-expected7] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[%=&%%=&&%%%=-False-expected8] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[%=&%%=&&%%%=-True-expected9] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[+=&%+=&&%++=-True-expected10] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[=x=&=x=+1=x=&%=x-False-expected11] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[%=+&%=&+%+=&%+&=%&=+%&+==%+&=%&+=+%&=+&%=&%+=&+%+%=&+%&=+=%&+=&%+&%=+&=%&%=+&%+=&=%+&=+%&+%=&+=%-False-expected12] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[%%%\x00%\x00==\x00\x00==-True-expected13] tests/test_utils.py::TestFalconUtils::test_parse_query_string_edge_cases[spade=\u2660&spade=\u2660-False-expected14] tests/test_utils.py::TestFalconUtils::test_parse_host tests/test_utils.py::TestFalconUtils::test_get_http_status tests/test_utils.py::TestFalconUtils::test_code_to_http_status[703-703 tests/test_utils.py::TestFalconUtils::test_code_to_http_status[404-404 tests/test_utils.py::TestFalconUtils::test_code_to_http_status[404.9-404 tests/test_utils.py::TestFalconUtils::test_code_to_http_status[123-123] tests/test_utils.py::TestFalconUtils::test_code_to_http_status_neg[not_a_number] tests/test_utils.py::TestFalconUtils::test_code_to_http_status_neg[0_0] tests/test_utils.py::TestFalconUtils::test_code_to_http_status_neg[0_1] tests/test_utils.py::TestFalconUtils::test_code_to_http_status_neg[99_0] tests/test_utils.py::TestFalconUtils::test_code_to_http_status_neg[99_1] tests/test_utils.py::TestFalconUtils::test_code_to_http_status_neg[404.3] tests/test_utils.py::TestFalconUtils::test_code_to_http_status_neg[-404.3_0] tests/test_utils.py::TestFalconUtils::test_code_to_http_status_neg[-404] tests/test_utils.py::TestFalconUtils::test_code_to_http_status_neg[-404.3_1] tests/test_utils.py::TestFalconUtils::test_http_status_to_code[HTTPStatus.HTTP_VERSION_NOT_SUPPORTED-505_0] tests/test_utils.py::TestFalconUtils::test_http_status_to_code[712-712_0] tests/test_utils.py::TestFalconUtils::test_http_status_to_code[712-712_1] tests/test_utils.py::TestFalconUtils::test_http_status_to_code[404 tests/test_utils.py::TestFalconUtils::test_http_status_to_code[712 tests/test_utils.py::TestFalconUtils::test_http_status_to_code[123 tests/test_utils.py::TestFalconUtils::test_http_status_to_code[HTTPStatus.HTTP_VERSION_NOT_SUPPORTED-505_1] tests/test_utils.py::TestFalconUtils::test_http_status_to_code_neg[0] tests/test_utils.py::TestFalconUtils::test_http_status_to_code_neg[ tests/test_utils.py::TestFalconUtils::test_http_status_to_code_neg[1] tests/test_utils.py::TestFalconUtils::test_http_status_to_code_neg[12] tests/test_utils.py::TestFalconUtils::test_http_status_to_code_neg[99] tests/test_utils.py::TestFalconUtils::test_http_status_to_code_neg[catsup] tests/test_utils.py::TestFalconUtils::test_http_status_to_code_neg[2] tests/test_utils.py::TestFalconUtils::test_http_status_to_code_neg[5.2] tests/test_utils.py::TestFalconUtils::test_etag_dumps_to_header_format tests/test_utils.py::TestFalconUtils::test_etag_strong_vs_weak_comparison tests/test_utils.py::TestFalconUtils::test_secure_filename[.-_] tests/test_utils.py::TestFalconUtils::test_secure_filename[..-_.] tests/test_utils.py::TestFalconUtils::test_secure_filename[hello.txt-hello.txt] tests/test_utils.py::TestFalconUtils::test_secure_filename[\u0104\u017euolai tests/test_utils.py::TestFalconUtils::test_secure_filename[/etc/shadow-_etc_shadow] tests/test_utils.py::TestFalconUtils::test_secure_filename[. tests/test_utils.py::TestFalconUtils::test_secure_filename[C:\\Windows\\kernel32.dll-C__Windows_kernel32.dll] tests/test_utils.py::TestFalconUtils::test_secure_filename_empty_value tests/test_utils.py::test_simulate_request_protocol[asgi-https-CONNECT] tests/test_utils.py::test_simulate_request_protocol[asgi-https-DELETE] tests/test_utils.py::test_simulate_request_protocol[asgi-https-GET] tests/test_utils.py::test_simulate_request_protocol[asgi-https-HEAD] tests/test_utils.py::test_simulate_request_protocol[asgi-https-OPTIONS] tests/test_utils.py::test_simulate_request_protocol[asgi-https-PATCH] tests/test_utils.py::test_simulate_request_protocol[asgi-https-POST] tests/test_utils.py::test_simulate_request_protocol[asgi-https-PUT] tests/test_utils.py::test_simulate_request_protocol[asgi-https-TRACE] tests/test_utils.py::test_simulate_request_protocol[asgi-http-CONNECT] tests/test_utils.py::test_simulate_request_protocol[asgi-http-DELETE] tests/test_utils.py::test_simulate_request_protocol[asgi-http-GET] tests/test_utils.py::test_simulate_request_protocol[asgi-http-HEAD] tests/test_utils.py::test_simulate_request_protocol[asgi-http-OPTIONS] tests/test_utils.py::test_simulate_request_protocol[asgi-http-PATCH] tests/test_utils.py::test_simulate_request_protocol[asgi-http-POST] tests/test_utils.py::test_simulate_request_protocol[asgi-http-PUT] tests/test_utils.py::test_simulate_request_protocol[asgi-http-TRACE] tests/test_utils.py::test_simulate_request_protocol[wsgi-https-CONNECT] tests/test_utils.py::test_simulate_request_protocol[wsgi-https-DELETE] tests/test_utils.py::test_simulate_request_protocol[wsgi-https-GET] tests/test_utils.py::test_simulate_request_protocol[wsgi-https-HEAD] tests/test_utils.py::test_simulate_request_protocol[wsgi-https-OPTIONS] tests/test_utils.py::test_simulate_request_protocol[wsgi-https-PATCH] tests/test_utils.py::test_simulate_request_protocol[wsgi-https-POST] tests/test_utils.py::test_simulate_request_protocol[wsgi-https-PUT] tests/test_utils.py::test_simulate_request_protocol[wsgi-https-TRACE] tests/test_utils.py::test_simulate_request_protocol[wsgi-http-CONNECT] tests/test_utils.py::test_simulate_request_protocol[wsgi-http-DELETE] tests/test_utils.py::test_simulate_request_protocol[wsgi-http-GET] tests/test_utils.py::test_simulate_request_protocol[wsgi-http-HEAD] tests/test_utils.py::test_simulate_request_protocol[wsgi-http-OPTIONS] tests/test_utils.py::test_simulate_request_protocol[wsgi-http-PATCH] tests/test_utils.py::test_simulate_request_protocol[wsgi-http-POST] tests/test_utils.py::test_simulate_request_protocol[wsgi-http-PUT] tests/test_utils.py::test_simulate_request_protocol[wsgi-http-TRACE] tests/test_utils.py::test_simulate_free_functions[asgi-simulate_get] tests/test_utils.py::test_simulate_free_functions[asgi-simulate_head] tests/test_utils.py::test_simulate_free_functions[asgi-simulate_post] tests/test_utils.py::test_simulate_free_functions[asgi-simulate_put] tests/test_utils.py::test_simulate_free_functions[asgi-simulate_options] tests/test_utils.py::test_simulate_free_functions[asgi-simulate_patch] tests/test_utils.py::test_simulate_free_functions[asgi-simulate_delete] tests/test_utils.py::test_simulate_free_functions[wsgi-simulate_get] tests/test_utils.py::test_simulate_free_functions[wsgi-simulate_head] tests/test_utils.py::test_simulate_free_functions[wsgi-simulate_post] tests/test_utils.py::test_simulate_free_functions[wsgi-simulate_put] tests/test_utils.py::test_simulate_free_functions[wsgi-simulate_options] tests/test_utils.py::test_simulate_free_functions[wsgi-simulate_patch] tests/test_utils.py::test_simulate_free_functions[wsgi-simulate_delete] tests/test_utils.py::TestFalconTestingUtils::test_path_escape_chars_in_create_environ tests/test_utils.py::TestFalconTestingUtils::test_no_prefix_allowed_for_query_strings_in_create_environ tests/test_utils.py::TestFalconTestingUtils::test_plus_in_path_in_create_environ tests/test_utils.py::TestFalconTestingUtils::test_none_header_value_in_create_environ tests/test_utils.py::TestFalconTestingUtils::test_decode_empty_result[asgi] tests/test_utils.py::TestFalconTestingUtils::test_decode_empty_result[wsgi] tests/test_utils.py::TestFalconTestingUtils::test_httpnow_alias_for_backwards_compat tests/test_utils.py::TestFalconTestingUtils::test_default_headers[wsgi] tests/test_utils.py::TestFalconTestingUtils::test_default_headers_with_override[wsgi] tests/test_utils.py::TestFalconTestingUtils::test_status[wsgi] tests/test_utils.py::TestFalconTestingUtils::test_wsgi_iterable_not_closeable tests/test_utils.py::TestFalconTestingUtils::test_path_must_start_with_slash[wsgi] tests/test_utils.py::TestFalconTestingUtils::test_cached_text_in_result[wsgi] tests/test_utils.py::TestFalconTestingUtils::test_simple_resource_body_json_xor[SimpleTestResource] tests/test_utils.py::TestFalconTestingUtils::test_simple_resource_body_json_xor[SimpleTestResourceAsync] tests/test_utils.py::TestFalconTestingUtils::test_query_string[wsgi] tests/test_utils.py::TestFalconTestingUtils::test_query_string_no_question[wsgi] tests/test_utils.py::TestFalconTestingUtils::test_query_string_in_path[wsgi] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[asgi-16.0625] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[asgi-123456789] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[asgi-True] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[asgi-] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[asgi-I tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[asgi-document5] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[asgi-document6] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[asgi-document7] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[wsgi-16.0625] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[wsgi-123456789] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[wsgi-True] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[wsgi-] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[wsgi-I tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[wsgi-document5] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[wsgi-document6] tests/test_utils.py::TestFalconTestingUtils::test_simulate_json_body[wsgi-document7] tests/test_utils.py::TestFalconTestingUtils::test_simulate_remote_addr[wsgi-None] tests/test_utils.py::TestFalconTestingUtils::test_simulate_remote_addr[wsgi-127.0.0.1] tests/test_utils.py::TestFalconTestingUtils::test_simulate_remote_addr[wsgi-8.8.8.8] tests/test_utils.py::TestFalconTestingUtils::test_simulate_remote_addr[wsgi-104.24.101.85] tests/test_utils.py::TestFalconTestingUtils::test_simulate_remote_addr[wsgi-2606:4700:30::6818:6455] tests/test_utils.py::TestFalconTestingUtils::test_simulate_hostname[wsgi] tests/test_utils.py::TestFalconTestingUtils::test_simulate_with_environ_extras[extras0-expected_headers0] tests/test_utils.py::TestFalconTestingUtils::test_simulate_with_environ_extras[extras1-expected_headers1] tests/test_utils.py::TestFalconTestingUtils::test_override_method_with_extras[wsgi] tests/test_utils.py::TestNoApiClass::test_something tests/test_utils.py::TestSetupApi::test_something tests/test_utils.py::test_get_argnames tests/test_utils.py::TestContextType::test_attributes[CustomContextType] tests/test_utils.py::TestContextType::test_attributes[Context] tests/test_utils.py::TestContextType::test_items_from_attributes[CustomContextType] tests/test_utils.py::TestContextType::test_items_from_attributes[Context] tests/test_utils.py::TestContextType::test_attributes_from_items[CustomContextType] tests/test_utils.py::TestContextType::test_attributes_from_items[Context] tests/test_utils.py::TestContextType::test_dict_interface[CustomContextType-CustomContextType] tests/test_utils.py::TestContextType::test_dict_interface[Context-Context] tests/test_utils.py::TestContextType::test_keys_and_values[CustomContextType] tests/test_utils.py::TestContextType::test_keys_and_values[Context] tests/test_utils.py::TestDeprecatedArgs::test_method tests/test_utils.py::TestDeprecatedArgs::test_function